Android群英传——类QQ侧滑菜单栏效果

本文介绍如何使用ViewDragHelper实现侧滑菜单效果,并对比DrawerLayout和SlidingPaneLayout的不同实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文使用ViewDragHelper实现类qq侧滑菜单栏的效果,同时也简单介绍了DrawerLayout和SlidingPanLayout实现侧滑效果的方法。

ViewDragHelper

Google在其support库中为我们提供了DrawerLayout和SlidingPaneLayout两个布局来实现侧滑效果,两个强大的布局背后是通过ViewDragHelper来实现的,ViewDragHelper基本可以实现各种不同的滑动,拖放,这个方法是各种滑动方案中的终极绝招。

类QQ侧滑菜单栏的效果图:

这里写图片描述

ViewDragHelper的使用步骤:

1. 使用静态工厂方法初始化ViewDragHelper

2. 拦截事件,通过onInterceptTouchEcent将事件传递给ViewDragHelper进行处理

3. 重写computeScroll()通过Scroller类来实现平滑移动

4.callback回调事件 

使用静态工厂初始化ViewDragHelper


 mViewDragHelper = ViewDragHelper.create(this, callback);

//另一种写法
mViewDragHelper = ViewDragHelper.create(this, 1.0f, callback);

其中1.0f是敏感度参数参数越大越敏感。(官方文档中指明 1.0f 是默认值)。第一个参数为this,表示该类生成的对象,他是ViewDragHelper的拖动处理对象,必须为ViewGroup。


将事件传递给ViewDragHelper来处理

  //拦截事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将触摸事件传递给ViewDragHelper
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

重写computeScroll(),使用continueSettling来判断移动是否还在继续,如果还在移动,我们就调用postInvalidateOnAnimation()方法进行刷新

 @Override
    public void computeScroll() {
        super.computeScroll();
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

我们要实现侧滑效果,我们首先要获取到子View,然后再让子View做相应的位置改变。这里我们布局的设置是:MainView覆盖MenuView,让MenuView固定,MainView滑动来显示出MenuView。

   //获取子布局
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }

tryCaptureView方法是用来决定哪些view是可以移动的,这里我们让子View 中的mMainView移动,所以返回 child == mMainView; 如果直接返回true,那么所有的子View都是可以移动的。

clampViewPositionHorizontal返回一个适当的数值就能实现横向拖动效果,默认为0。第二个参数是指当前拖动子view应该到达的x坐标。所以按照常理这个方法原封返回第二个参数就可以了,为了让被拖动的view遇到边界之后就不再拖动,可以对返回的值做更多的考虑。

clampViewPositionVertical是指竖直方向

onViewReleased用来实现手指离开屏幕后的操作。在这里我们进行判断,当滑动的位置大于500,打开菜单栏,即MainView移动到固定的位置,将MenuView显示出来。否则,不显示。注意使用 ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);进行刷新。

  ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        //主要对mMainView来进行触摸移动
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }

        //水平滑动
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

    //实现手指离开屏幕后的操作
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
           if (mMainView.getLeft() > 500) {//当滑动的距离超过500,打开菜单
                mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                //刷新
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
           else {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);

            }

        }
    };

完整代码:

public class DragViewGroup extends FrameLayout {
    private View mMainView;
    private View mMenuView;
    private ViewDragHelper mViewDragHelper;


    public DragViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //使用静态工厂方法初始化ViewDragHelper
        mViewDragHelper = ViewDragHelper.create(this, callback);
    }

    //callback回调
    ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        //主要对mMainView来进行触摸移动
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }

        //水平滑动
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        //实现手指离开屏幕后的操作
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
           if (mMainView.getLeft() > 500) {//当滑动的距离超过500,打开菜单
                mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                //刷新
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
           else {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);

            }

        }
    };

    //获取子布局
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }

    //拦截事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将触摸事件传递给ViewDragHelper
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}

布局代码:

<RelativeLayout 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"
    tools:context=".MainActivity">
    <example.com.myapplication2.DragViewGroup
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorAccent"
            >
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="menu"
            />
        </FrameLayout>
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorPrimary"
            >
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="main"
                />
        </FrameLayout>
    </example.com.myapplication2.DragViewGroup>
</RelativeLayout>

探究

1.我们将上述代码中下面这段代码删除,即不做view移动后的处理,那么MainView就会跟随手指移动。

这里写图片描述

 //实现手指离开屏幕后的操作
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
           if (mMainView.getLeft() > 500) {//当滑动的距离超过500,打开菜单
                mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                //刷新
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
           else {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);

            }

        }

2.在原代码的基础上,添加竖直滑动,那么从竖直方向我们也可以滑动菜单栏

这里写图片描述

  @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }

对手指离开屏幕后的操作进行修改

 //实现手指离开屏幕后的操作
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
           if (mMainView.getLeft() > 500) {//当滑动的距离超过500,打开菜单
                mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                //刷新
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
            else if (mMainView.getTop() > 500) {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 300);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            } else {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);

            }

        }
    };

3.我们将tryCaptureView返回true,即让所有view都能滑动,再添加上水平方向的滑动,竖直方向上的滑动,把onViewReleased删除,那么我们就可以实现所有view跟随手指移动。
这里写图片描述

 //callback回调
    ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

        //水平滑动
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        //竖直滑动
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }
    };

DrawerLayout

DrawerLayout只是一个布局,在这个布局中允许放置两个空间,第一个控件是主屏幕的内容,第二个子控件是滑动菜单栏的内容。我们只需要对activity_main做修改,就可以实现滑动效果,注意滑动菜单栏要设置背景颜色,否则默认颜色和阴影相似,导致无法区分。layout_gravity这个属性是必须要指明的,在这里指定为start,表示会根据系统语言进行判断,如果系统语言是从左往右,滑动菜单栏就在左边,如英语,汉语。如果系统语言从右往左,如阿拉伯语,滑动菜单栏在右边。

这里写图片描述

<android.support.v4.widget.DrawerLayout 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"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff"
        android:text="This is Menu"
        android:gravity="center"
        android:textSize="30dp"
        android:layout_gravity="start"
        />

</android.support.v4.widget.DrawerLayout>

SlidingPaneLayout

SlidingPaneLayout也是布局,只需要在布局中设置好相应的布局就可以实现侧滑的效果。

这里写图片描述

<android.support.v4.widget.SlidingPaneLayout 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"
    tools:context=".MainActivity">
    <TextView
        android:text="this is Menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="30dp"
        android:background="@color/colorAccent"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary"
        android:text="Hello world"
        android:gravity="center"
        android:textSize="30dp"
        />

</android.support.v4.widget.SlidingPaneLayout>
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值