Android Sliding View

(博主认为这个View写得实在是有很多问题,大家仅供参考,之后一定会更新)

很多应用中都可以见到一种像窗户一样的可以侧滑的View。左右滑动可以出现诸如:设置选项之类的东西:

例如人人的客户端:



现在我们也来做一个这样的View:


1,我们三个页面的布局特别简单,只是背景为纯色的线性布局:

这里重点在SlidingView上,置于页面显示什么,还有其他功能可以自己完善。

left_layout.xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/red"
    android:orientation="vertical" >
    

</LinearLayout>

 middle_layout.xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/green"
    android:orientation="vertical" >
    

</LinearLayout>

right_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/bule"
    android:orientation="vertical" >
    

</LinearLayout>

2,我们自定义一个继承FrameLayout的SlidingView ,由它构成主布局:

sliding_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.flyingduck.slidinglayoutdemo.view.SlidingLayoutView
        android:id="@+id/sliding_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <include
            android:id="@+id/left_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            layout="@layout/left_layout" />

        <include
            android:id="@+id/right_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            layout="@layout/right_layout" />

        <include
            android:id="@+id/middle_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            layout="@layout/middle_layout" />
    </com.flyingduck.slidinglayoutdemo.view.SlidingLayoutView>

</RelativeLayout>

3,SlidingView

package com.flyingduck.slidinglayoutdemo.view;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TableLayout;

public class SlidingLayoutView extends FrameLayout implements OnTouchListener {
    
    private final static String TAG = "SlidingLayoutView";

    /* ---------- Layout ---------- */
    private View leftLayout;
    private View middleLayout;
    private View rightLayout;

    /* ---------- LayoutParams---------- */
    private MarginLayoutParams leftLayoutParams;
    private MarginLayoutParams middleLayoutParams;
    private MarginLayoutParams rightLayoutParams;
    
    /* ---------- Data Parameter---------- */
    private int screenWidth;
    /** the x coordinate of finger press **/
    private float xDown;
    /** the coordinate of finger move **/
    private float xMove;
    /** the coordinate of finger up **/
    private float xUp;
    
    /** the width of left layout when it is visible. default is a quarter to screenWidth**/
    private int leftVisibleWidth;
    /** the width of right layout when it is visible. default is three quarter to screenWidth **/
    private int rightVisibleWidth;
    
    /* ---------- flag ---------- */
    /** weather the left layout is visible. default is false **/
    private boolean isLeftLayoutVisible = false;
    /** weather the middle layout is visible. default is true **/
    private boolean isMiddleLayoutVisible = true;
    /** weather the right layout is visible. default is false **/
    private boolean isRightLayoutVisible = false;
    /** current sliding status **/
    private boolean isSliding = false;
    
    
    /** velocity tracker : user for calculate the sliding velocity of finger<br>
     * initialize when call touch event via createVelocityTracker(event) method<br>
     * <br>
     * Helper for tracking the velocity of touch events, for implementing flinging and other such gestures. Use obtain() to retrieve a new instance of the class when you are going to begin tracking. Put the motion events you receive into it with addMovement(MotionEvent). When you want to determine the velocity call computeCurrentVelocity(int) and then call getXVelocity(int) and getYVelocity(int) to retrieve the velocity for each pointer id.
     * **/
    private VelocityTracker velocityTracker;
    
    /** the lower limit of sliding velocity that can switch over **/
    private int FINGER_SNAP_MIN_VELOCITY = 200;
    
    private int SLIDING_SPEED = 30;
    
    /** the view which binded can respond to touch event **/
    private View bindView;
    
    private SlidTask slidTask;
    
    /** four direction when sliding **/
    public static final int LEFT2MIDDLE = 1;
    public static final int MIDDLE2RIGHT = 2;
    public static final int RIGHT2MIDDLE = -2;
    public static final int MIDDLE2LEFT = -1;
    
    /* ---------- Constructor ---------- */
    public SlidingLayoutView(Context context) {
        super(context);
    }

    public SlidingLayoutView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public SlidingLayoutView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initData(context);
    }

    private void initData(Context context) {
        WindowManager windManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        screenWidth = windManager.getDefaultDisplay().getWidth();
        leftVisibleWidth = screenWidth/2;
        rightVisibleWidth = (screenWidth*3)/4;
        
        Log.i(TAG, "left width & right width" + leftVisibleWidth + " & " + rightVisibleWidth);
    }

    /* ---------- OnLayout ---------- */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed){
            // get the left layout
            leftLayout = getChildAt(0);
            leftLayoutParams = (MarginLayoutParams) leftLayout.getLayoutParams();
            leftLayoutParams.width = leftVisibleWidth;
            leftLayoutParams.leftMargin = 0;
            leftLayout.setLayoutParams(leftLayoutParams);
            
            // get the middle layout
            middleLayout = getChildAt(2);
            middleLayoutParams = (MarginLayoutParams) middleLayout.getLayoutParams();
            middleLayoutParams.width = screenWidth;
            middleLayoutParams.leftMargin = 0;
            middleLayout.setLayoutParams(middleLayoutParams);
            
            // get the right layout
            rightLayout = getChildAt(1);
            rightLayoutParams = (MarginLayoutParams) rightLayout.getLayoutParams();
            rightLayoutParams.width = rightVisibleWidth;
            rightLayoutParams.leftMargin = screenWidth - rightVisibleWidth;
            rightLayout.setLayoutParams(rightLayoutParams);
            if (isLeftLayoutVisible){
                leftLayout.setVisibility(View.VISIBLE);
                rightLayout.setVisibility(View.GONE);
                middleLayoutParams.leftMargin = leftVisibleWidth;
                middleLayout.setLayoutParams(rightLayoutParams);
            }else if (isRightLayoutVisible){
                leftLayout.setVisibility(View.GONE);
                rightLayout.setVisibility(View.VISIBLE);
                middleLayoutParams.leftMargin = -rightVisibleWidth;
                middleLayout.setLayoutParams(middleLayoutParams);
            }else{
                middleLayoutParams.leftMargin = 0;
                middleLayout.setLayoutParams(middleLayoutParams);
                leftLayout.setVisibility(View.GONE);
                rightLayout.setVisibility(View.GONE);
            }
            
            this.layout(left, top, right, bottom);
        }
        
    }

    /* ---------- OnTouchListener Method ---------- */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        createVelocityTracker(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (isSliding()){
                isSliding = false;
            }
            xDown = event.getRawX();
            break;
        case MotionEvent.ACTION_MOVE:
            xMove = event.getRawX();
            int xDistance = (int) (xMove - xDown);
            
            int leftMargin = middleLayoutParams.leftMargin;
            
            /** 调整中间布局的位置 **/
            if (isLeftLayoutVisible){
                leftMargin = leftVisibleWidth + xDistance;
                leftLayout.setVisibility(View.VISIBLE);
                rightLayout.setVisibility(View.GONE);
            }else if (isRightLayoutVisible){
                leftMargin = -rightVisibleWidth + xDistance;
                leftLayout.setVisibility(View.GONE);
                rightLayout.setVisibility(View.VISIBLE);
            }else{
                leftMargin = xDistance;
                if (xDistance > 0){
                    leftLayout.setVisibility(View.VISIBLE);
                    rightLayout.setVisibility(View.GONE);
                }else{
                    leftLayout.setVisibility(View.GONE);
                    rightLayout.setVisibility(View.VISIBLE);
                }
            }
            
            Log.i(TAG, "leftmargin" + leftMargin);
            
            if (isLeftLayoutVisible){
                if (leftMargin >= leftVisibleWidth){
                    leftMargin = leftVisibleWidth;
                }else if (leftMargin <=0){
                    leftMargin = 0;
                }
            }else if(isMiddleLayoutVisible){
                if (leftMargin >= leftVisibleWidth){
                    leftMargin = leftVisibleWidth;
                }else if (leftMargin <= -rightVisibleWidth){
                    leftMargin = -rightVisibleWidth;
                }
            }else{
                if (leftMargin >= 0){
                    leftMargin = 0;
                }else if(leftMargin<= -rightVisibleWidth){
                    leftMargin = -rightVisibleWidth;
                }
            }

            middleLayoutParams.leftMargin = leftMargin;
            middleLayout.setLayoutParams(middleLayoutParams);
            
            break;
        case MotionEvent.ACTION_UP:
            xUp = event.getRawX();
                int slidMode = 0;
                if (isWant2ShowLeftLayout()){
                    if (isShouldSlid2Another()){
                        slidMode = MIDDLE2LEFT;
                    }else{
                        slidMode = LEFT2MIDDLE;
                    }
                }else if (isWant2ShowMiddleLayout()){
                    if (isShouldSlid2Another()){
                        if (isLeftLayoutVisible){
                            slidMode = LEFT2MIDDLE;
                            
                        }else{
                            slidMode = RIGHT2MIDDLE;
                        }
                    }else{
                        if (isLeftLayoutVisible){
                            slidMode = MIDDLE2LEFT;
                        }else{
                            slidMode = MIDDLE2RIGHT;
                        }
                        
                    }
                }else if(isWant2ShowRightLayout()){
                    if (isShouldSlid2Another()){
                        slidMode = MIDDLE2RIGHT;
                    }else{
                        slidMode = RIGHT2MIDDLE;
                    }
                }
                slid(slidMode);
            
            recycleVelocityTracker(); 
            break;
        default:
            break;
        }
        
        Log.i(TAG, isLeftLayoutVisible+" : "+isMiddleLayoutVisible+" : "+isRightLayoutVisible);
        
        
        return isBindbasicLayout();
    }
    
    /* ---------- Private Method ---------- */
    /**
     * initialize VelocityTracker and add touch event to velocitytracker
     */
    private void createVelocityTracker(MotionEvent event) {
        if (velocityTracker == null){
            velocityTracker = VelocityTracker.obtain();
        }
        velocityTracker.addMovement(event);
    }
    
    /**
     * get sliding velocity of finger 
     */
    private int getSlidingVelocity(){
        velocityTracker.computeCurrentVelocity(1000);
        return (int) Math.abs(velocityTracker.getXVelocity());
    }
    
    /**
     *recycle velocity tracker 
     */
    private void recycleVelocityTracker(){
        velocityTracker.recycle();
        velocityTracker = null;
    }
    
    /**
     * judge weather hava intent to show the left layout.
     */
    private boolean isWant2ShowLeftLayout() {
        return xUp - xDown > 0 && !isLeftLayoutVisible && isMiddleLayoutVisible;
    }
    
    /**
     * judge weather hava intent to show the middle layout
     */
    private boolean isWant2ShowMiddleLayout(){
        return (isLeftLayoutVisible && !isMiddleLayoutVisible && xUp - xDown < 0)
                ||(isRightLayoutVisible && !isMiddleLayoutVisible && xUp - xDown > 0);
    }
    
    /**
     *judge weather hava intent to show the right layout 
     */
    private boolean isWant2ShowRightLayout(){
        return xUp - xDown < 0 && !isRightLayoutVisible && isMiddleLayoutVisible;
    }
    /**
     * judge weather should slid to other layout 
     */
    private boolean isShouldSlid2Another(){
        return Math.abs(xUp - xDown) > screenWidth/2 || getSlidingVelocity() > FINGER_SNAP_MIN_VELOCITY;
    }
    
    /**
     * judge the binded view weather is a basic layout(LinearLayout,RelativeLayout,FrameLayout,TableLayout)
     */
    private boolean isBindbasicLayout(){
        if (bindView == null){
            return false;
        }
        String bindViewName = bindView.getClass().getName();
        return bindViewName.equals(LinearLayout.class.getName()) || bindViewName.equals(RelativeLayout.class.getName()) 
                || bindViewName.equals(FrameLayout.class.getName()) || bindViewName.equals(TableLayout.class.getName());
    }
    
    /** according to the mode to decide the speed of sliding
     * and start to slid **/
    private void slid(int mode){
        int speed = 0;
        switch (mode) {
        case LEFT2MIDDLE:
            isLeftLayoutVisible = false;
            isMiddleLayoutVisible = true;
            speed = -SLIDING_SPEED;
            break;
        case MIDDLE2RIGHT:
            isMiddleLayoutVisible = false;
            isRightLayoutVisible = true;
            speed = -SLIDING_SPEED;
            break;
        case RIGHT2MIDDLE:
            isRightLayoutVisible = false;
            isMiddleLayoutVisible = true;
            speed = SLIDING_SPEED;
            break;
        case MIDDLE2LEFT:
            isMiddleLayoutVisible = false;
            isLeftLayoutVisible = true;
            speed = SLIDING_SPEED;
            break;
        default:
            break;
        }
        isSliding = true;
        slidTask = new SlidTask();
        slidTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, speed, mode);
    }
    
    private void sleep(long mills){
        try {
            Thread.sleep(mills);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private boolean isSliding(){
        return isSliding;
    }
    
    
    
    /* ---------- Public Method ---------- */
    
    /**
     * bind the view of monitor slid event
     */
    public void addSlidEvent(View bindView){
        this.bindView = bindView;
        bindView.setOnTouchListener(this);
    }
    
    public void refresh(){
        this.requestLayout();
    }
    
    
    /* ---------- Slid Task---------- */
    private final class SlidTask extends AsyncTask<Integer, Integer, Integer>{

        @Override
        protected Integer doInBackground(Integer... speed) {
            int leftMargin = middleLayoutParams.leftMargin;
            boolean done = false;
            while(!done && isSliding()){
                leftMargin += speed[0];
                switch (speed[1]) {
                case LEFT2MIDDLE:
                    if (leftMargin <= 0){
                        leftMargin = 0;
                        done = true;
                    }
                    break;
                case MIDDLE2RIGHT:
                    if (leftMargin <= -rightVisibleWidth){
                        leftMargin = -rightVisibleWidth;
                        done = true;
                    }
                    break;
                case RIGHT2MIDDLE:
                    if (leftMargin >= 0){
                        leftMargin = 0;
                        done = true;
                    }
                    break;
                case MIDDLE2LEFT:
                    if (leftMargin >= leftVisibleWidth){
                        leftMargin = leftVisibleWidth;
                        done = true;
                    }
                    break;
                default:
                    break;
                }
                
                publishProgress(leftMargin);
                sleep(20);
            }
            
            return leftMargin;
        }
        
        @Override
        protected void onProgressUpdate(Integer... leftMargin) {
            middleLayoutParams.leftMargin = leftMargin[0];
            middleLayout.setLayoutParams(middleLayoutParams);
        }
        
        @Override
        protected void onPostExecute(Integer leftMargin) {
            middleLayoutParams.leftMargin = leftMargin;
            middleLayout.setLayoutParams(middleLayoutParams);
            isSliding = false;
        }
    }
    
}



4,MainActivity

package com.flyingduck.slidinglayoutdemo;

import com.flyingduck.slidinglayoutdemo.view.SlidingLayoutView;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

public class MainActivity extends Activity {
	

    private SlidingLayoutView slidingLayout;
    private LinearLayout leftLayout;
    private LinearLayout rightLayout;
    private LinearLayout middleLayout;
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.sliding_layout);
		initView();
		
//		slidingLayout.addSlidEvent(leftLayout);
		slidingLayout.addSlidEvent(middleLayout);
//		slidingLayout.addSlidEvent(rightLayout);
	}
	
	private void initView(){
	    slidingLayout = (SlidingLayoutView) findViewById(R.id.sliding_layout);
	    leftLayout = (LinearLayout) findViewById(R.id.left_layout);
	    middleLayout = (LinearLayout) findViewById(R.id.middle_layout);
	    rightLayout = (LinearLayout) findViewById(R.id.right_layout);
	    
	    
	    
	}

}

addSlidEvent()本可以在SlidingLayoutView中不必公开出来。这里只设置了中间布局的touch事件。


效果图:







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值