Android之 左右滑動菜單


近來學習了極客學院有關於界面左右滑動的視頻,就在這里寫個博客,鞏固一下知識點,以免忘了。

這里主要介紹界面是如何左右滑動的:

1.首先我們應該設置好將要滑動的三個界面,即leftMenu、middleMenu、rightMenu三個布局,並且放置好它們的位置,這段大家自己在源碼中看

2.當位置放好后,就可以開始關於滑動方面的代碼。

頁面的滑動是通過點的坐標變化距離來進行來實現的。首先我們定義了20dp來確保最小下限滑動的距離,來確定是否進行了滑動;接着就可以進行判斷頁面的滑動方向,ACTION_DOWN、ACTION_MOVE、ACTION-UP分別對應了手指點擊時的按下,移動,抬起時的事件。當按下時,我們獲取此時點擊點的坐標,隨后我們實時獲取活動過程中點的滑動坐標,后者減去前者就得到了滑動的距離。當滑動的距離大於TEST_DIS時,如果此時在左右滑動的距離大於在上下滑動距離,就置isLeftRightFragment為true,用於下面的判斷。

private Point point = new  Point();
    private boolean isLeftRightFragment;
    //設置比較值20;當移動小於20dp時,默認沒有移動
    private static final int TEST_DIS = 20;
    private void getTypeEvent(MotionEvent ev) {
        switch (ev.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            point.x = (int) ev.getX();
            point.y = (int) ev.getY();
            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>TEST_DIS&&dX>dY) {           //左右滑動
                isLeftRightFragment = true;
                isTestCompete = true;
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
            }else if (dY>TEST_DIS&&dY>dX) {     //上下滑動
                isLeftRightFragment = false;
                isTestCompete = true;
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
            }

            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            break;
        default:
            break;
        }    
    }

3.這部分一些地方我也不太明白,大家看我寫的注釋吧,沒有的地方我也不太懂(比如回調的方法是干嘛的,Action_move下面的兩行代碼,知道的給我留言啊)。

    public boolean isTestCompete;
    public int finalX=0;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!isTestCompete) {
            getTypeEvent(ev);
            return true;
        }
        if (isLeftRightFragment) {
            switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_MOVE:
                int curScrollX = getScrollX();      //獲取滑動的距離,向左為負,向右為正
                int dis_x = (int) (ev.getX() - point.x);
                int expectX = -dis_x + curScrollX;
                if (expectX<0) {
          //向左滑動
finalX
= Math.max(expectX, -leftMenu.getMeasuredWidth()); }else {           //向右滑動
finalX
= Math.min(expectX, rightMenu.getMeasuredWidth()); }           //跟隨點的滑動,頁面滑動
scrollTo(finalX,
0); point.x= (int) ev.getX(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: curScrollX = getScrollX(); if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) { //當滑動的距離大於外布局寬度的一半時 if (curScrollX < 0) { //向左滑動,前兩個參數是開始時坐標,中間是將要移動的距離,200是動畫的時間單位毫秒
mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0 ,200); }else { //向右滑動 mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200); } }else { //小於寬度的一半,自動返回原位 mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200); } invalidate(); //view的重繪 isLeftRightFragment = false; isTestCompete = false; break; } }else { switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: isLeftRightFragment = false; isTestCompete = false; break; default: break; } } return super.dispatchTouchEvent(ev); } //回調的方法 @Override public void computeScroll() { super.computeScroll(); if (!mScroller.computeScrollOffset()) { return; } int tempX = mScroller.getCurrX(); scrollTo(tempX, 0); }

4.三完成后,就可以實現頁面滑動了,第四步是在頁面滑動時,中間的那個布局會變暗。思路是在定義一個布局middleMask,將它的位置和顏色設置完畢。初始化中設置透明度middleMask.setAlpha(0);

再在重寫的ScrollTo方法中設置middleMask的透明度跟隨移動漸變。

@Override
    public void scrollTo(int x, int y) {
        
        super.scrollTo(x, y);
     // 設置middlemask的透明度隨移動距離漸變
        int curX = Math.abs(getScrollX());
        //scale的范圍為0-1
        float scale = curX/ (float)leftMenu.getMeasuredWidth();
        middleMask.setAlpha(scale);
    }

 

源碼:

MainActivity:

public class MainActivity extends ActionBarActivity {

    private MenuUI menuUI;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        menuUI=new MenuUI(this); 
        setContentView(menuUI);
    }
}

MenuUI:

public class MenuUI extends RelativeLayout{
    private Context context;
    private FrameLayout leftMenu;
    private FrameLayout middleMenu;
    private FrameLayout rightMenu;
    private FrameLayout middleMask;
    private Scroller mScroller;
    
    
    public MenuUI(Context context) {
        super(context);
        initView(context);
        
    }
    
    public MenuUI(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }
    //初始化
    private void initView(Context context){
        this.context=context;
        mScroller = new Scroller(context, new DecelerateInterpolator());    //第二個參數為渲染器
        leftMenu = new FrameLayout(context);
        middleMenu = new FrameLayout(context);
        rightMenu = new FrameLayout(context);
        middleMask = new FrameLayout(context);
        leftMenu.setBackgroundColor(Color.YELLOW);
        middleMenu.setBackgroundColor(Color.GREEN);
        rightMenu.setBackgroundColor(Color.YELLOW);
        middleMask.setBackgroundColor(0x88000000);
        addView(leftMenu);
        addView(middleMenu);
        addView(rightMenu);
        addView(middleMask);
        //設置透明度
        middleMask.setAlpha(0);  
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
        middleMask.measure(widthMeasureSpec, heightMeasureSpec);
        //得到菜單的寬的大小
        int realWidth = MeasureSpec.getSize(widthMeasureSpec);
        //令tempRealtempwidth等於菜單0.8倍的寬,用於設置左右菜單的寬度
        int tempRealWidth = MeasureSpec.makeMeasureSpec((int)(realWidth*0.8f),
                MeasureSpec.EXACTLY);
        //設置左右菜單的大小
        leftMenu.measure(tempRealWidth, heightMeasureSpec);
        rightMenu.measure(tempRealWidth, heightMeasureSpec);
    }
    
    public float onMiddleMask(){
        System.out.println("透明度:"+middleMask.getAlpha());
        return middleMask.getAlpha();
    }
    
    @Override
    public void scrollTo(int x, int y) {
        
super.scrollTo(x, y);
     // 設置middlemask的透明度隨移動距離漸變
int curX = Math.abs(getScrollX()); //scale的范圍為0-1 float scale = curX/ (float)leftMenu.getMeasuredWidth(); middleMask.setAlpha(scale); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //設置各個布局菜單的位置 super.onLayout(changed, l, t, r, b); //將中間界面的位置設置為l,t,r,b middleMenu.layout(l, t, r, b); middleMask.layout(l, t, r, b); //根據middleMenu的位置確定其他菜單的位置 leftMenu.layout(l-leftMenu.getMeasuredWidth(), t, r-middleMenu.getMeasuredWidth(), b); rightMenu.layout(l+middleMenu.getMeasuredWidth(), t, l+rightMenu.getMeasuredWidth()+middleMenu.getMeasuredWidth(), b); } public boolean isTestCompete; public int finalX=0; @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!isTestCompete) { getTypeEvent(ev); return true; } if (isLeftRightFragment) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_MOVE: int curScrollX = getScrollX(); //獲取滑動的距離,向左為負,向右為正 int dis_x = (int) (ev.getX() - point.x); int expectX = -dis_x + curScrollX; if (expectX<0) { finalX = Math.max(expectX, -leftMenu.getMeasuredWidth()); }else { finalX = Math.min(expectX, rightMenu.getMeasuredWidth()); } scrollTo(finalX, 0); point.x= (int) ev.getX(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: curScrollX = getScrollX(); if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) { //當滑動的距離大於外布局寬度的一半時 if (curScrollX < 0) { //向左滑動 mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth()-curScrollX, 0 ,200); }else { //向右滑動 mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth()-curScrollX, 0,200); } }else { //小於寬度的一半,自動返回原位 mScroller.startScroll(curScrollX, 0, -curScrollX, 0,200); } invalidate(); //view的重繪 isLeftRightFragment = false; isTestCompete = false; break; } }else { switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: isLeftRightFragment = false; isTestCompete = false; break; default: break; } } return super.dispatchTouchEvent(ev); } //回調的方法 @Override public void computeScroll() { super.computeScroll(); if (!mScroller.computeScrollOffset()) { return; } int tempX = mScroller.getCurrX(); scrollTo(tempX, 0); }
private Point point = new Point(); private boolean isLeftRightFragment; private static final int TEST_DIS = 20;
private void getTypeEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: point.x = (int) ev.getX(); point.y = (int) ev.getY(); 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>TEST_DIS&&dX>dY) { //左右滑動 isLeftRightFragment = true; isTestCompete = true; point.x = (int) ev.getX(); point.y = (int) ev.getY(); }else if (dY>TEST_DIS&&dY>dX) { //上下滑動 isLeftRightFragment = false; isTestCompete = true; point.x = (int) ev.getX(); point.y = (int) ev.getY(); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; default: break; } } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM