1. 程式人生 > >自定義左右滑動選單

自定義左右滑動選單

存一個自定義滑動選單:

記一些關鍵的函式作用:

1.定義一個FrameLayout fm,fm.measure(width,height)代表定義這個fm的長和寬。
2.onMeasure()用於測量父Layout裡面的各個layout,onLayout用於佈局父Layout裡面的各個layout。
3.實際操作滑動距離的時候用下面的程式碼:

int scrollX = getScrollX();
                    int dX = (int) ev.getX() - point.x;
                    int finalX = 0;
                    int exX = scrollX - dX;
                    if(exX > 0){
                        finalX = Math.max(exX,-leftFrame.getMeasuredWidth());          //最多隻能滑到右邊的邊界
                        scrollTo(finalX,0);                 //滑動操作
                    }
                    else{
                        finalX = Math.min(exX,rightFrame.getMeasuredWidth());          //最多隻能滑到左邊的邊界
                        scrollTo(finalX,0);
                    }

4.更新了蒙版效果,在滑倒其他頁面時,主頁面會進行灰度的漸變。
5.添加了事件監聽。
MainActivity.Java

package com.example.a53125.slidingrelativelayouttest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private MainUI mainUI;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainUI = new MainUI(this);
        setContentView(mainUI);
    }
}

MainUI.Java

package com.example.a53125.slidingrelativelayouttest;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.support.annotation.Px;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;



/**
 * Created by 53125 on 2017/8/16.
 */

public class MainUI extends RelativeLayout {
    @android.support.annotation.IdRes
    int LEFT_ID = 0xaabbcc;
    @android.support.annotation.IdRes
    int MID_ID = 2222;
    @android.support.annotation.IdRes
    int RIGHT_ID = 3333;
    private Context context;
    private FrameLayout middleFrame;
    private FrameLayout leftFrame;
    private FrameLayout rightFrame;
    private FrameLayout maskFrame;
    private Scroller scroller;
//    public static int LEFT_ID = 0xaabbcc;
//    public final int MID_ID = 2222;
//    public final int RIGHT_ID = 3333;

    public MainUI(Context context) {
        super(context);
        this.context = context;
        initView(context);
    }

    public MainUI(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public void initView(Context context){
        scroller = new Scroller(context,new DecelerateInterpolator());
        middleFrame = new FrameLayout(context);
        leftFrame = new FrameLayout(context);
        rightFrame = new FrameLayout(context);
        maskFrame = new FrameLayout(context);
        middleFrame.setBackgroundColor(Color.GREEN);
        leftFrame.setBackgroundColor(Color.YELLOW);
        rightFrame.setBackgroundColor(Color.YELLOW);
        maskFrame.setBackgroundColor(0x88000000);
        maskFrame.setAlpha(0);
        leftFrame.setId(LEFT_ID);
        middleFrame.setId(MID_ID);
        rightFrame.setId(RIGHT_ID);
        addView(leftFrame);
        addView(middleFrame);
        addView(rightFrame);
        addView(maskFrame);
    }

    @Override
    public void scrollTo(@Px int x, @Px int y) {
        super.scrollTo(x, y);
        int scr = Math.abs(getScrollX());
        float alpha = scr/(float) leftFrame.getMeasuredWidth();
        maskFrame.setAlpha(alpha);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        middleFrame.measure(widthMeasureSpec,heightMeasureSpec);
        maskFrame.measure(widthMeasureSpec,heightMeasureSpec);
        int Screen_Width = MeasureSpec.getSize(widthMeasureSpec);
//        System.out.println("widthMeasureSpec:"+widthMeasureSpec);
//        System.out.println("Screen_Width"+Screen_Width);
        int Left_Width = MeasureSpec.makeMeasureSpec((int)(Screen_Width*0.8f),MeasureSpec.EXACTLY);
        leftFrame.measure(Left_Width,heightMeasureSpec);
        rightFrame.measure(Left_Width,heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        middleFrame.layout(l, t, r, b);
        maskFrame.layout(l, t, r, b);
        leftFrame.layout(l-leftFrame.getMeasuredWidth(), t, r, b);
        rightFrame.layout(l+middleFrame.getMeasuredWidth(), t, r+rightFrame.getMeasuredWidth(), b);
    }

    private int state = 0;
    private boolean stateSlidingLeftRight = false;        //是否左右滑動
    private boolean stateSlidingUpDown = false;        //是否上下滑動
    private int TEST_DIS = 20;             //滑動判定的最小距離
    Point point = new Point();

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
//        System.out.println("Click successfully!");
//        System.out.println("LeftWidth:"+leftFrame.getMeasuredWidth());
//        System.out.println("MidWidth:"+middleFrame.getMeasuredWidth());
        if(!(state == 1)){

            getState(ev);
//            System.out.println("stateSlidingLeftRight:"+stateSlidingLeftRight);
            return true;                  //一定要返回true,否則的話不會進行滑動操作
        }
        if(stateSlidingUpDown){                    //用於初始化橫向滑動的狀態,便於接著上次再次滑動
            stateSlidingLeftRight = false;
            state = 0;
        }
        if(stateSlidingLeftRight){
            System.out.println("Sliding successfully!");
            switch (ev.getActionMasked()){
                case MotionEvent.ACTION_MOVE:
                    int scrollX = getScrollX();
                    int dX = (int) ev.getX() - point.x;
                    int finalX = 0;
                    int exX = scrollX - dX;
                    if(exX > 0){
                        finalX = Math.max(exX,-leftFrame.getMeasuredWidth());          //最多隻能滑到右邊的邊界
                        scrollTo(finalX,0);                 //滑動操作
                    }
                    else{
                        finalX = Math.min(exX,rightFrame.getMeasuredWidth());          //最多隻能滑到左邊的邊界
                        scrollTo(finalX,0);
                    }
                    point.x = (int) ev.getX();                 //儲存點,用於下一次滑動
                    point.y = (int) ev.getY();
                    break;
                case MotionEvent.ACTION_UP:              //用於初始化橫向滑動的狀態,便於接著上次再次滑動
                case MotionEvent.ACTION_CANCEL:         //用於初始化橫向滑動的狀態,便於接著上次再次滑動
                    int scroll = getScrollX();
                    if(Math.abs(scroll) > leftFrame.getMeasuredWidth() >>1){
                        if(scroll < 0){
                            scroller.startScroll(scroll,0,-leftFrame.getMeasuredWidth()-scroll,0);
                        }
                        else{
                            scroller.startScroll(scroll,0,leftFrame.getMeasuredWidth()-scroll,0);
                        }
                    }
                    else{
                        scroller.startScroll(scroll,0,-scroll,0);
                    }
                    invalidate();
                    stateSlidingLeftRight = false;
                    state = 0;
                    break;
                default:break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if(!scroller.computeScrollOffset()){
            return;
        }
        int tempX = scroller.getCurrX();
        scrollTo(tempX,0);
    }

    private void getState(MotionEvent ev) {
        switch (ev.getActionMasked()){
            case MotionEvent.ACTION_UP:        //手指擡起後觸發
                state = 0;
                stateSlidingLeftRight = false;
                stateSlidingUpDown = false;
                super.dispatchTouchEvent(ev);
                break;
            case MotionEvent.ACTION_DOWN:        //手指按下的一瞬間觸發
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
                super.dispatchTouchEvent(ev);
                break;
            case MotionEvent.ACTION_CANCEL:      //手指滑到邊界觸發
                stateSlidingLeftRight = false;
                state = 0;
                dispatchTouchEvent(ev);
                break;
            case MotionEvent.ACTION_MOVE:         //手指滑動觸發
                int dX = Math.abs((int)ev.getX() - point.x);
                int dY = Math.abs((int)ev.getY() - point.y);
                if(dX > dY && dX > TEST_DIS){         //滑動舉例大於TEST_DIS才算滑動
                    stateSlidingLeftRight = true;
                    stateSlidingUpDown = false;
                    state = 1;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }else if(dX < dY && dY > TEST_DIS){
                    stateSlidingUpDown = true;
                    stateSlidingLeftRight = false;
                    state = 1;
                    point.x = (int) ev.getX();          //記錄點用於下次滑動
                    point.y = (int) ev.getY();
                }
                break;

        }
    }

}