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;
        }
    }
}
时间: 2024-08-06 15:51:22

Android之 左右滑动菜单的相关文章

android实现左右滑动菜单

直接看效果图:       主要实现代码: package com.way.view; import android.content.Context; import android.media.DeniedByServerException; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import and

Android 3D滑动菜单完全解析,实现推拉门式的立体特效

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10471245 在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一个例子,实现了类似于API Demos里的图片中轴旋转功能.不过那个例子的核心代码是来自于API Demos中带有的Rotate3dAnimation这个类,是它帮助我们完成了所有的三维旋转操作,所有Matrix和Camera相关的代码也是封装在这个类中. 这样说来的话,大家心里会不会痒痒的呢?虽然

Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个朋友在评论中留言,希望我可以帮他将这个滑动菜单改成双向滑动的方式.当时也没想花太多时间,简单修改了一下就发给了他,结果没想到后来却有一大批的朋友都来问我要这份双向滑动菜单的代码.由于这份代码写得很不用心,我发了部分朋友之后实在不忍心继续发下去了,于是决定专门写一篇文章来介绍更好的Android双向滑

Android 学习笔记之AndBase框架学习(七) SlidingMenu滑动菜单的实现

PS:努力的往前飞..再累也无所谓.. 学习内容: 1.使用SlidingMenu实现滑动菜单..   SlidingMenu滑动菜单..滑动菜单在绝大多数app中也是存在的..非常的实用..Github有位牛人将这个东西书写成了一个简单的框架..我们只需要通过引用相关的资源就能够完成一个滑动菜单的实现..有了这一层的基础..那么滑动菜单就很容易实现了..就拿我们最为熟悉的QQ来说吧..当我们进行滑动操作的时候..会有一个新的View去覆盖原本的View..我们可以通过触发新的视图上的控件来执行

它们的定义android滑动菜单

在这里实现了两个滑动菜单效果,的拖放内容的第一部分,菜单拖出像这样的效果感觉,另一种是拖动内容.后面的内容固定菜单.我感觉有层次感的效果,如下面 第一种效果的代码实现例如以下: package com.tenghu.customsideslip.menu.view; import android.content.Context; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.D

Android 自定义ViewGroup,实现侧方位滑动菜单

侧方位滑动菜单 1.现在adnroid流行的应用当中很多都是用的侧方位滑动菜单如图: 将菜单显示在左边,内容页面显示在右边,通过滑动或则按钮点击来隐藏和显示菜单. 2.首先对ViewGroup进行个了解: View是ViewGroup的父类,ViewGroup具有View的所有特性,ViewGroup主要用用来充当View的容器,将其中的View作为自己孩子, 并对其进行管理,当然孩子也是可以是ViewGroup类型. View类一般用于绘图操作,重写他的onDraw方法,但它不可以包含其他组件

【转】Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个朋友在评论中留言,希望我可以帮他将这个滑动菜单改成双向滑动的方式.当时也没想花太多时间,简单修改了一下就发给了他,结果没想到后来却有一大批的朋友都来问我要这份双向滑动菜单的代码.由于这份代码写得很不用心,我发了部分朋友之后实在不忍心继续发下去了,于是决定专门写一篇文章来介绍更好的Android双向滑

Android 滑动菜单SlidingMenu

首先我们看下面视图: 这种效果大家都不陌生,网上好多都说是仿人人网的,估计人家牛逼出来的早吧,我也参考了一一些例子,实现起来有三种方法,我下面简单介绍下: 方法一:其实就是对GestureDetector手势的应用及布局文件的设计. 布局文件main.xml    采用RelativeLayout布局. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=&quo

android ——滑动菜单

DrawerLayout是一个拥有两个子控件的布局,第一个子控件是主屏幕中显示的内容,第二个子控件是滑动菜单中显示的内容: 1 <android.support.v4.widget.DrawerLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 android:id=