QQ测拉效果实现(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32059827/article/details/78064601

前言:总有一天,你会成为你想象的那样。

转载本文请注明出处,尊重原创:

如果想第一时间收到文章更新,可以微信扫描二维码关注我的公众号,或者微信直接搜索“Android小菜”进行关注,所有的文章会比CSDN更快一步:

觉得有帮助可以赞赏或者点个赞,都是对博主的支持。

本篇文章开始连续三篇会实现类似QQ测拉效果的自定义控件。分别使用不同的方式来实现同一效果。


本篇使用方式一来实现:HorizontalScrollView + LinearLayout + scrollTo + 属性动画。

说明:HorizontalScrollView 自动实现了滑动功能,里面放置一个LinearLayout,LinearLayout横向里面放置两个控件,左侧菜单+主页面布局。



本文会从基本功能再到“特效”的步骤循序进行。


首先不加入动画,先实现基本侧滑功能,要实现的功能如下gif:

基础功能由于很简单,直接把代码贴在下面:

public class QQSlidingMenu extends HorizontalScrollView {

    /**
     * 屏幕宽度
     */
    private final int mScreenWidth;

    /**
     * 代表左侧菜单和内部区域的父容器
     */
    private LinearLayout mWapper;

    /**
     * 左侧菜单区域
     */
    private ViewGroup mLeftMenu;

    /**
     * 主页面内容区域
     */
    private ViewGroup mContentMenu;

    /**
     * 左侧菜单完全展示距离右侧的距离值dp
     */
    private int mLeftMenuRightPadding = 50;

    /**
     * 左侧菜单的宽度
     */
    private int mLeftMenuWidth;

    /**
     * onMeasure只测量一次
     */
    private boolean once;

    public QQSlidingMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取屏幕宽度
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
        mScreenWidth = metrics.widthPixels;

        /**---------  dp--->px  ---------**/
        mLeftMenuRightPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,context.getResources().getDisplayMetrics());
    }

    /**
     * 测量孩子的大小,确定自己的大小
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if(!once){

            mWapper = (LinearLayout) this.getChildAt(0);
            mLeftMenu = (ViewGroup) mWapper.getChildAt(0);
            mContentMenu = (ViewGroup) mWapper.getChildAt(1);

            //设置左右菜单的宽度
            mLeftMenuWidth = mLeftMenu.getLayoutParams().width = mScreenWidth - mLeftMenuRightPadding;
            mContentMenu.getLayoutParams().width = mScreenWidth;

            once = true;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }


    /**
     * 摆放孩子控件的位置,确定自己的位置
     * 通过设置偏移量让左侧菜单隐藏
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(changed){
            scrollTo(mLeftMenuWidth,0);
        }
    }

    //滑动事件HorizontalScrollView已经帮忙给处理了,所以不需要down和move的操作
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                // 判断目前滑动到的位置,让控件过度到某种状态
                // 如果左侧菜单滑动超过了左侧菜单的一半则展示左侧菜单,如果滑动少于左侧菜单一半则展示主页面,隐藏左菜单
                int scrollX = getScrollX();
                if(scrollX >= mLeftMenuWidth/2){
                    smoothScrollTo(mLeftMenuWidth,0);
                }else{
                    smoothScrollTo(0,0);
                }
                return true;
         }

        return super.onTouchEvent(ev);

    }
}

没错,上面十几行代码就实现了最基本功能了。因为HorizontalScrollView 已经具备了处理滑动事件的功能,我们只需要关心在哪个位置抬起手指(鼠标),以及让控件平滑滑动到哪个位置。

然后对上面的代码做个解析:

首先在构造方法里面拿到屏幕的宽度,这个宽度待会要设置HorizontalScrollView孩子控件的宽度,接着是dp-->px的转换,因为要设置左侧菜单控件距离屏幕右侧的Padding值,这里定义为50dp。

然后重写onMeasure方法,在里面分别测量了自定义QQSlidingMenu控件的孩子控件的大小,因为布局文件中QQSlidingMenu的xml里面是一个水平的LinearLayout控件,它里面包含了两个布局,分别是左侧菜单的布局,和主页内容的布局。然后首先拿到LinearLayout实例,再根据getChildAt(i),分别拿到左侧菜单和主页内容的布局实例,强转为ViewGroup类型。为了方式多次测量,定义了一个标志位,表示只需要测量一次。对于左侧菜单的宽度=屏幕宽度-距离右侧的padding值;对于主页面的宽度就为屏幕的宽度。

然后重写onLayout方法,对孩子控件进行位置包房,由于默认情况下是下面摆放:

其中紫色区域是自定义的QQSlidingMenu。显然默认是错误的,因此要改变控件的位置,看到只是简单的一行代码就设置了控件的初识位置。scrollTo到左侧菜单的宽度,那么测试的效果如下:

布局摆放好了,往下就是滑动事件了,发现也很简单,因为咱们是继承的HorizontalScrollView ,它已经默认做好了MOVE和DOWN事件了,所以只需要判断一下UP事件就可以了。在UP的时候,判断目前滑动到的位置,让控件过度到某种状态(是显示菜单还是隐藏菜单);如果左侧菜单往右滑动超过了左侧菜单的一半则展示左侧菜单,如果往右滑动少于左侧菜单一半则展示主页面,隐藏左菜单。并调用smoothScrollTo,让布局平滑过渡到某个值。然后说一下getScroll()这个值是多少,看下面一张图:

灰色笔描述的就是getScroll()值,他表示控件相对屏幕划过的距离,值大于0,表示控件是左滑得到的值,小于0,表示控件右滑得到的值。


上面属于最基本的功能实现,我们考虑,在控件的代码中,我按照自己的意愿写了50dp的padding值,那么别人如果想设置为100dp,或者150dp怎么办,难道要修改代码吗?所以,有必要加入自定义属性,通过这种方式在xml中,手动设置padding,而不是去修改代码:

新建一个名称为attr的xml文件:

然后在这里面做一点文章:

上面是定义了一个属性,待会再xml布局中我们就要使用该自定义的属性。

QQSlidingMenu控件的构造方法中加入如下代码:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQSlidingMenu);
        int count = array.getIndexCount();

        for (int i = 0; i < count; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.QQSlidingMenu_mRightPadding:
                    mLeftMenuRightPadding = array.getDimensionPixelSize(attr,
                            (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,
                                    context.getResources().getDisplayMetrics()));
                    break;

                default:
                    break;
                }
        }

        array.recycle();

然后在布局文件中引入自定义属性:

我们自定义属性的方式,设置padding值为100dp,那么此时运行后,左侧菜单距离屏幕右侧的宽度肯定是会增加的。

此时运行程序看一下侧滑菜单展示的样式:


以上加上了自定义属性,紧接着,我们加上一个menu按钮,来实现点击按钮打开左侧菜单的功能:


在自定义QQSlidingMenu里面,加入如下打开和关闭的代码,并且提供一个共有的toogle方法:


当然,在滑动的时候,也要修改一下标志位:


再运行程序:



以上是本篇所讲内容,下一篇会修改这里的代码,加入一些动画,实现抽屉效果,



想第一时间查看文章,请关注公众号:“Android小菜”。











猜你喜欢

转载自blog.csdn.net/qq_32059827/article/details/78064601
今日推荐