自定义Android侧滑菜单控件

package com.tenghu.sideslipmenu.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/18.

 */

public class SideslipMenuView extends LinearLayout {

    //滚动显示和隐藏menu时,手指滑动需要达到的速度

    private static final int SNAP_VELOCITY = 200;

    private View mMenu;//菜单布局

    private View mContent;//主内容布局

    private int mScreenWidth;//屏幕宽度

    private int mMenuWidth;//菜单宽度

    //menu最多可以滑动到的左边缘,值由menu布局的宽度来定

    private int leftEdge;

    //menu最多可以滑到的有边缘,值恒为0

    private int rightEdge = 0;

    //menu完全显示时,留给content的宽度值

    private int toRightPaddingWidth = 50;

    //menu布局的参数,通过此参数来更改leftMargin的值

    private LinearLayout.LayoutParams menuParams;

    //记录手指按下的横坐标

    private float xDown;

    //记录手指抬起的横坐标

    private float xUp;

    //记录手指移动的横坐标

    private float xMove;

    //当前menu是显示还是隐藏,只有menu完全显示和隐藏才会改变该值,滑动时不会改变

    private boolean isMenuVisible;

    //用于计算手指滑动的速度

    private VelocityTracker mVelocityTracker;

    private boolean once;

    public SideslipMenuView(Context context) {

        super(context);

        init(context);

    }

    public SideslipMenuView(Context context, AttributeSet attrs) {

        super(context, attrs);

        init(context);

    }

    /**

     * 初始化

     */

    private void init(Context context) {

        //获取WindowManager对象

        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        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 = getChildAt(0);//获取菜单布局

            mContent = getChildAt(1);//获取内容布局

            menuParams = (LayoutParams) mMenu.getLayoutParams();//获取菜单参数

            mMenuWidth = menuParams.width = mScreenWidth - toRightPaddingWidth;//设置菜单宽度

            //左边缘的值赋值为menu宽度的负数

            leftEdge = -menuParams.width;

            //menu的leftMargin设置为左边缘的值,默认菜单不可见

            menuParams.leftMargin = leftEdge;

            mContent.getLayoutParams().width = mScreenWidth;//设置内容宽度

            once = true;

        }

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        createVelocityTracker(event);//创建VelocityTracker对象

        switch (event.getAction()) {

            //手指按下

            case MotionEvent.ACTION_DOWN:

                xDown = event.getRawX();//记录横坐标

                break;

            //手指移动

            case MotionEvent.ACTION_MOVE:

                //手指移动时,对比按下的横坐标,计算出移动的距离来调整menu的leftMargin值,从而显示和隐藏menu

                xMove = event.getRawX();

                //计算获取到距离

                int distanceX = (int) (xMove - xDown);

                if (isMenuVisible) {

                    menuParams.leftMargin = distanceX;

                } else {

                    menuParams.leftMargin = leftEdge + distanceX;

                }

                //如果菜单的左边界小于了可以滑动的左边界

                if (menuParams.leftMargin <= leftEdge) {

                    //将可以滑动的左边界赋值给菜单左边界

                    menuParams.leftMargin = leftEdge;

                } else if (menuParams.leftMargin >= rightEdge) {

                    menuParams.leftMargin = rightEdge;

                }

                mMenu.setLayoutParams(menuParams);//设置菜单参数

                break;

            //手指抬起

            case MotionEvent.ACTION_UP:

                //手指抬起时,进行判断当前手势的意图,从而决定是滚动到menu界面,还是滚动到content界面

                xUp = event.getRawX();

                if (wantToShowMenu()) {

                    if (shouldScrollToMenu()) {

                        scrollToMenu();

                    } else {

                        scrollToContent();

                    }

                } else if (wantToShowContent()) {

                    if (shouldScrollToContent()) {

                        scrollToContent();

                    } else {

                        scrollToMenu();

                    }

                }

                //手指抬起是回收VelocityTracker对象

                recycleVelocityTracker();

                break;

        }

        return true;

    }

    /**

     * 创建VelocityTracker对象,并将触摸content界面的滑动时间加入到VelocityTracker中

     *

     * @param event

     */

    private void createVelocityTracker(MotionEvent event) {

        if (null == mVelocityTracker) {

            mVelocityTracker = VelocityTracker.obtain();//初始化VelocityTracker

        }

        mVelocityTracker.addMovement(event);//添加界面滑动事件

    }

    /**

     * 判断当前手势的意图是不是想显示content,如果手指移动的距离是负数,且当前menu是可见的,则认为当前手势是想要显示content。

     *

     * @return

     */

    private boolean wantToShowContent() {

        return xUp - xDown < 0 && isMenuVisible;

    }

    /**

     * 判断当前手势的意图是不是想显示menu,如果手指移动的距离是正数,且当前menu是不可见,则认为当前手势是显示menu

     *

     * @return

     */

    private boolean wantToShowMenu() {

        return xUp - xDown > 0 && !isMenuVisible;

    }

    /**

     * 判断是否应该滚动将menu展示出来,如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,就认为应该滚动将menu展示出来。

     *

     * @return 如果应该滚动将menu展示出来返回true,否则返回false。

     */

    private boolean shouldScrollToMenu() {

        return xUp - xDown > mMenuWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;

    }

    /**

     * 判断是否应该滚动将content展示出来,如果手指移动距离加上menuPadding大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将content展示出来。

     *

     * @return 如果应该滚动将content展示出来返回true,否则返回false。

     */

    private boolean shouldScrollToContent() {

        //这里菜单状态为显示,如果要菜单隐藏,那么手势是从右到左滑动,这里手指按下的横坐标就会比抬起时的横坐标小

        return xDown - xUp + toRightPaddingWidth > mMenuWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;

    }

    /**

     * 获取手指在content上滑动的速度

     *

     * @return 滑动速度,以每秒钟移动了多少像素为单位

     */

    private int getScrollVelocity() {

        mVelocityTracker.computeCurrentVelocity(1000);

        int velocity = (int) mVelocityTracker.getXVelocity();//获取x方向的速度值

        return Math.abs(velocity);

    }

    /**

     * 回收VelocityTracker对象

     */

    private void recycleVelocityTracker() {

        if (null != mVelocityTracker) {

            mVelocityTracker.recycle();

            mVelocityTracker = null;

        }

    }

    /**

     * 将屏幕滚动到menu界面,设置滚动速度为30

     */

    private void scrollToMenu() {

        isMenuVisible = true;

        new ScrollTask().execute(30);

    }

    /**

     * 将屏幕滚动到content界面,设置滚动速度为-30

     */

    private void scrollToContent() {

        isMenuVisible = false;

        new ScrollTask().execute(-30);

    }

    /**

     * 创建滚动任务类

     */

    class ScrollTask extends AsyncTask<Integer, Integer, Integer> {

        @Override

        protected Integer doInBackground(Integer... speed) {

            int leftMargin = menuParams.leftMargin;

            //根据传入的速度来滚动界面,当滚动到达左边界或右边界时跳出循环

            while (true) {

                leftMargin = leftMargin + speed[0];

                if (leftMargin > rightEdge) {

                    leftMargin = rightEdge;

                    break;

                }

                if (leftMargin < leftEdge) {

                    leftMargin = leftEdge;

                    break;

                }

                //更新任务进度,会把值传入到onProgressUpdate()方法中进行UI的更新

                publishProgress(leftMargin);

                //为了要有滚动效果产生,每次循环使线程睡眠20毫秒

                sleep(20);

            }

            return leftMargin;

        }

        /**

         * 这里的Intege参数对应AsyncTask中的第二个参数

         * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行

         * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作

         *

         * @param leftMargin

         */

        @Override

        protected void onProgressUpdate(Integer... leftMargin) {

            menuParams.leftMargin = leftMargin[0];

            mMenu.setLayoutParams(menuParams);

        }

        /**

         * 执行异步结束,接收doInBackground()方法的返回值,接收到的返回值对应AsyncTask<Integer, Integer, Integer> 第3个参数

         *

         * @param leftMargin

         */

        @Override

        protected void onPostExecute(Integer leftMargin) {

            menuParams.leftMargin = leftMargin;

            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.sideslipmenu.view.SideslipMenuView xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    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"

        android:orientation="vertical">

       

    </LinearLayout>

</com.tenghu.sideslipmenu.view.SideslipMenuView>

其中include引用的就是一个菜单布局文件,如下:

<?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去布局,这里做测试就没有去使用了

当前题目:自定义Android侧滑菜单控件
标题网址:https://www.cdcxhl.com/article0/pgosoo.html

成都网站建设公司_创新互联,为您提供网页设计公司电子商务移动网站建设虚拟主机品牌网站设计

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

小程序开发