自定义android侧滑菜单

来源:互联网 发布:数据分析体系架构 编辑:程序博客网 时间:2024/05/22 09:44

这里实现两种侧滑菜单效果,第一种拖拽内容部分,菜单像是被拖出来的感觉的这种效果,第二种是拖拽内容部分,菜单在内容后面不动,感觉有一种层次感的效果,如下



第一种效果的代码实现如下:

package com.tenghu.customsideslip.menu.view;import android.content.Context;import android.os.AsyncTask;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.WindowManager;import android.widget.LinearLayout;/** * Created by Arvin_Li on 2014/11/19. */public class ScrollSideslipMenu extends LinearLayout{    private static final int SNAP_VELOCITY=200;//速度阈值    private View mMenu;//菜单布局    private View mContent;//内容布局    private int screenWidth;//屏幕宽度    private int menuWidth;//菜单宽度    private int leftEdge;//左边界    private int rightEdge=0;//右边界,值恒为0    private float xUp;//手指抬起时记录横坐标    private float xDown;//手指按下时记录横坐标    private float xMove;//手指移动时记录横坐标    private int toRightPaddingWidth=50;//菜单完全显示时,留给内容的宽度    private LayoutParams menuParams;//菜单布局参数    private boolean once=false;//初始化数据只加载一次    private boolean isShowMenu;//是否显示菜单    private VelocityTracker velocityTracker;//速度跟踪器    public ScrollSideslipMenu(Context context) {        super(context);        initWindowWidth(context);    }    public ScrollSideslipMenu(Context context, AttributeSet attrs) {        super(context, attrs);        initWindowWidth(context);    }    /**     * 初始化获取屏幕宽度     */    private void initWindowWidth(Context context){        WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics displayMetrics=new DisplayMetrics();        windowManager.getDefaultDisplay().getMetrics(displayMetrics);        //获取屏幕宽度        screenWidth=displayMetrics.widthPixels;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        if(!once){            mMenu=this.getChildAt(0);//获取菜单布局            mContent=this.getChildAt(1);//获取内容布局            menuParams= (LayoutParams) mMenu.getLayoutParams();//获取菜单布局参数            menuWidth=menuParams.width=screenWidth-toRightPaddingWidth;//设置菜单宽度            mContent.getLayoutParams().width=screenWidth;//设置内容宽度            leftEdge=-menuWidth;//左边界            menuParams.leftMargin=leftEdge;//默认菜单不显示            once=true;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        createVelocityTracker(event);        switch (event.getAction()){            //按下            case MotionEvent.ACTION_DOWN:                xDown=event.getRawX();//记录按下时的横坐标                break;            //移动            case MotionEvent.ACTION_MOVE:                //记录移动时的横坐标                xMove=event.getRawX();                //计算移动时与按下时的距离                int moveDistanceX= (int) (xMove-xDown);                if(isShowMenu){                    menuParams.leftMargin=moveDistanceX;                }else{                    menuParams.leftMargin=leftEdge+moveDistanceX;                }                if(menuParams.leftMargin<leftEdge){                    menuParams.leftMargin=leftEdge;                }                if(menuParams.leftMargin>rightEdge){                    menuParams.leftMargin=rightEdge;                }                mMenu.setLayoutParams(menuParams);//设置参数                break;            //抬起            case MotionEvent.ACTION_UP:                //记录抬起时的横坐标                xUp=event.getRawX();                //计算抬起时与按下时的距离                int upDistanceX= (int) (xUp-xDown);                if(upDistanceX>0&&!isShowMenu){                    if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){                        scrollToMenu();                    }else{                        scrollToContent();                    }                }else if(upDistanceX<0&&isShowMenu){                    if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){                        scrollToContent();                    }else{                        scrollToMenu();                    }                }                mMenu.setLayoutParams(menuParams);                break;        }        return true;    }    /**     * 滚动内容部分     */    private void scrollToContent(){        new ScrollTask().execute(-30);    }    /**     * 滚动菜单部分     */    private void scrollToMenu(){        new ScrollTask().execute(30);    }    /**     * 创建速度阈值     */    private void createVelocityTracker(MotionEvent event){        if(null==velocityTracker){            velocityTracker=VelocityTracker.obtain();        }        velocityTracker.addMovement(event);    }    /**     * 获取滚动时的速度     * @return     */    private int getScrollVelocity(){        velocityTracker.computeCurrentVelocity(1000);        int velocity= (int) velocityTracker.getXVelocity();//获取横向速度        return Math.abs(velocity);    }    /**     * 创建一个异步滚动任务     */    class ScrollTask extends AsyncTask<Integer,Integer,Integer>{        @Override        protected Integer doInBackground(Integer... params) {            int leftMargin=menuParams.leftMargin;            while(true){                leftMargin=leftMargin+params[0];                if(leftMargin<leftEdge){                    leftMargin=leftEdge;                    break;                }                if(leftMargin>rightEdge){                    leftMargin=rightEdge;                    break;                }                publishProgress(leftMargin);                sleep(20);            }            if(params[0]>0){                isShowMenu=true;            }else{                isShowMenu=false;            }            return leftMargin;        }        /**         * 执行结束         * @param integer         */        @Override        protected void onPostExecute(Integer integer) {            menuParams.leftMargin=integer;            mMenu.setLayoutParams(menuParams);        }        /**         * 执行doInBackground中的publishProgress调用该方法         * @param values         */        @Override        protected void onProgressUpdate(Integer... values) {            menuParams.leftMargin=values[0];            mMenu.setLayoutParams(menuParams);        }    }    /**     * 当前线程睡眠多少毫秒     * @param millis     */    private void sleep(long millis){        try {            Thread.sleep(millis);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

布局文件:

<?xml version="1.0" encoding="utf-8"?><com.tenghu.customsideslip.menu.view.ScrollSideslipMenu xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"    android:background="@drawable/bg_01">    <!--引用菜单布局文件-->    <include layout="@layout/left_menu"/>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@drawable/bg_02"></LinearLayout></com.tenghu.customsideslip.menu.view.ScrollSideslipMenu>

第二种效果实现:

package com.tenghu.customsideslip.menu.view;import android.content.Context;import android.os.AsyncTask;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.WindowManager;import android.widget.RelativeLayout;/** * Created by Arvin_Li on 2014/11/19. */public class CustomSideslipMenu extends RelativeLayout {    private static final int SNAP_VELOCITY=200;//手势滑动的速度    //屏幕宽度    private int mScreenWidth;    //菜单布局    private View mMenu;    //主体内容部分    private View mContent;    //声明菜单宽度    private int menuWidth;    //菜单完全显示时,留给内容部分的宽度    private int toRightPaddingWidth=50;    //主体内容布局参数    private LayoutParams contentParams;    //主体内容滑动到左边缘,由菜单宽度来决定    private int leftEdge;    //菜单显示时,主体内容到右边界,值恒为0    private int rightEdge=0;    private VelocityTracker velocityTracker;//声明速度跟踪器    private float xDown;//记录手指按下的横坐标    private float xUp;//记录手指抬起时的横坐标    private float xMove;//记录手指移动时的横坐标    private boolean once=false;//只执行一次    private boolean isShowMenu=true;//是否显示菜单    public CustomSideslipMenu(Context context) {        super(context);        init(context);    }    public CustomSideslipMenu(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    /**     * 初始化     */    private void init(Context context){        //获取窗口管理类        WindowManager windowManager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        //创建DisplayMetrics        DisplayMetrics displayMetrics=new DisplayMetrics();        windowManager.getDefaultDisplay().getMetrics(displayMetrics);        //获取屏幕宽度        mScreenWidth=displayMetrics.widthPixels;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        if(!once){            //获取菜单布局            mMenu=this.getChildAt(0);            //获取主体内容布局            mContent=this.getChildAt(1);            contentParams= (LayoutParams) mContent.getLayoutParams();//获取主体菜单参数            //菜单宽度            menuWidth=mMenu.getLayoutParams().width=mScreenWidth-toRightPaddingWidth;            //设置主体内容的宽度            mContent.getLayoutParams().width=mScreenWidth;            leftEdge=menuWidth;//设置左边界            once=true;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        //调用创建速度跟踪器        createVelocityTracker(event);        switch (event.getAction()){            //手指按下            case MotionEvent.ACTION_DOWN:                xDown=event.getRawX();                break;            //手指移动            case MotionEvent.ACTION_MOVE:                xMove=event.getRawX();                //计算移动距离                int distanceX= (int) (xMove-xDown);                if(isShowMenu){                    contentParams.leftMargin=distanceX;                    contentParams.rightMargin=-distanceX;                }else{                    contentParams.leftMargin=leftEdge+distanceX;                }                if(contentParams.leftMargin>leftEdge){                    contentParams.leftMargin=leftEdge;                    contentParams.rightMargin=-leftEdge;                }                if(contentParams.leftMargin<rightEdge){                    contentParams.leftMargin=rightEdge;                    contentParams.rightMargin=rightEdge;                }                mContent.setLayoutParams(contentParams);//测试参数                break;            //手指抬起            case MotionEvent.ACTION_UP:                xUp=event.getRawX();//手指抬起时横坐标                //计算抬起时与按下时的距离                int upDistanceX=(int) (xDown-xUp);                if(upDistanceX>0&&!isShowMenu){                        if(upDistanceX>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){                            scrollToMenu();                        }else{                            scrollToContent();                        }                }else if(upDistanceX<0&&isShowMenu){                    if(Math.abs(upDistanceX)>menuWidth/2||getScrollVelocity()>SNAP_VELOCITY){                        scrollToContent();                    }else{                        scrollToMenu();                    }                    //手指抬起时销毁                    recycleVelocityTracker();                }                break;        }        return true;    }    /**     * 滚动菜单     */    private void scrollToMenu(){        new ScrollTask().execute(-30);    }    /**     * 滚动内容     */    private void scrollToContent(){        new ScrollTask().execute(30);    }    /**     * 获取速度     * @return     */    private int getScrollVelocity(){        velocityTracker.computeCurrentVelocity(1000);        int velocity= (int) velocityTracker.getXVelocity();        return Math.abs(velocity);    }    /**     * 销毁速度跟踪器     */    private void recycleVelocityTracker(){        if (null != velocityTracker) {            velocityTracker.recycle();            velocityTracker = null;        }    }    /**     * 创建速度跟踪器     */    private void createVelocityTracker(MotionEvent event){        if(null==velocityTracker){            velocityTracker=velocityTracker.obtain();        }        velocityTracker.addMovement(event);    }    /**     * 创建异步滚动任务类     */    class ScrollTask extends AsyncTask<Integer,Integer,Integer>{        @Override        protected Integer doInBackground(Integer... params) {            int leftMargin=contentParams.leftMargin;            while(true){                leftMargin=leftMargin+params[0];                if(leftMargin>leftEdge){                    leftMargin=leftEdge;                    break;                }                if(leftMargin<rightEdge){                    leftMargin=rightEdge;                    break;                }                if(params[0]<0){                    isShowMenu=true;                   // leftMargin=rightEdge;                }else{                    isShowMenu=false;                }                publishProgress(leftMargin);                sleep(20);            }            return leftMargin;        }        @Override        protected void onProgressUpdate(Integer... values) {            contentParams.leftMargin=values[0];           contentParams.rightMargin=-values[0];            mContent.setLayoutParams(contentParams);        }        @Override        protected void onPostExecute(Integer integer) {            contentParams.leftMargin=integer;           contentParams.rightMargin=-integer;            mContent.setLayoutParams(contentParams);        }    }    /**     * 当前线程睡眠多少毫秒     * @param millis     */    private void sleep(long millis){        try {            Thread.sleep(millis);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

布局文件:

<com.tenghu.customsideslip.menu.view.CustomSideslipMenu 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"    android:background="@drawable/bg_01"    tools:context=".MainActivity">    <include layout="@layout/left_menu" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:background="@drawable/bg_02"            android:orientation="vertical">            <Button                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:onClick="testScrollMenu"                android:text="测试第二种侧滑菜单"/>        </LinearLayout>    </LinearLayout></com.tenghu.customsideslip.menu.view.CustomSideslipMenu>

菜单布局文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_vertical">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="30dp"        android:orientation="vertical">        <RelativeLayout            android:layout_width="wrap_content"            android:layout_height="50dp"            android:layout_marginBottom="10dp">            <ImageView                android:id="@+id/iv_img_01"                android:layout_width="50dp"                android:layout_height="match_parent"                android:src="@drawable/app_01" />            <TextView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_marginLeft="10dp"                android:layout_toRightOf="@id/iv_img_01"                android:gravity="center_vertical"                android:text="第一个Item" />        </RelativeLayout>        <RelativeLayout            android:layout_width="wrap_content"            android:layout_height="50dp"            android:layout_marginBottom="10dp">            <ImageView                android:id="@+id/iv_img_02"                android:layout_width="50dp"                android:layout_height="match_parent"                android:src="@drawable/app_02" />            <TextView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_marginLeft="10dp"                android:layout_toRightOf="@id/iv_img_02"                android:gravity="center_vertical"                android:text="第二个Item" />        </RelativeLayout>        <RelativeLayout            android:layout_width="wrap_content"            android:layout_height="50dp"            android:layout_marginBottom="10dp">            <ImageView                android:id="@+id/iv_img_03"                android:layout_width="50dp"                android:layout_height="match_parent"                android:src="@drawable/app_03" />            <TextView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_marginLeft="10dp"                android:layout_toRightOf="@id/iv_img_03"                android:gravity="center_vertical"                android:text="第三个Item" />        </RelativeLayout>        <RelativeLayout            android:layout_width="wrap_content"            android:layout_height="50dp"            android:layout_marginBottom="10dp">            <ImageView                android:id="@+id/iv_img_04"                android:layout_width="50dp"                android:layout_height="match_parent"                android:src="@drawable/app_04" />            <TextView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_marginLeft="10dp"                android:layout_toRightOf="@id/iv_img_04"                android:gravity="center_vertical"                android:text="第四个Item" />        </RelativeLayout>        <RelativeLayout            android:layout_width="wrap_content"            android:layout_height="50dp"            android:layout_marginBottom="10dp">            <ImageView                android:id="@+id/iv_img_05"                android:layout_width="50dp"                android:layout_height="match_parent"                android:src="@drawable/app_05" />            <TextView                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_marginLeft="10dp"                android:layout_toRightOf="@id/iv_img_05"                android:gravity="center_vertical"                android:text="第五个Item" />        </RelativeLayout>    </LinearLayout></RelativeLayout>

这里的菜单,可以是用ListView来布局,做测试就没有那样做了,所有代码全部在这里了,可以看出,两种效果只是继承了不通的布局,感觉第二种效果在设置背景时有点问题,就是在这里
<LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:background="@drawable/bg_02"            android:orientation="vertical">            <Button                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:onClick="testScrollMenu"                android:text="测试第二种侧滑菜单"/>        </LinearLayout>    </LinearLayout>
如果将背景设置到第一层的LinearLayout上,那么自定义侧滑菜单那里设置背景就显示不出来,设置到第二层就可以,不知道是肿么回事,如果各位大师找到了,麻烦告诉小弟。

0 0
原创粉丝点击