Android Scroll滑动效果精炼详解第(二)课:ViewDragHelper和简单实现QQ首页滑动效果

一、前期基础知识储备

经过前面Android Scrool滑动效果精炼详解第(一)课:基础理论和简单实现》的理论部分的讲解和实现的一个小示例,读者朋友应该对Android Scroll滑动效果有个基础的认知了,那么本节开始讲解实现滑动效果最重要的一种方法——使用ViewDragHelper类,通过ViewDragHelper,基本上可以实现各种不同的滑动、拖放需求,这个方法在《Android群英传》中被称为“实现滑动效果的终极绝招”

(1)ViewDragHelper类,上,官方文档

android.support.v4.widget.ViewDragHelper, ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup. 

由,官方文档,我们可知,ViewDragHelper是一个通用的类,专门用来对ViewGroup中的子类进行处理的,它提供了很多方法对子View进行移动和重新定位

二、上代码,具体实现

在本节中,笔者将带领大家一起实现一个仿QQ首页滑动效果的示例。使用的方法简单概括为:①自定义一个View,该View中放入两个子View;②运用ViewDragHelper类实现自定义视图的滑动效果

代码较长,先上运行效果图:

 

第二个界面的自定义View视图代码如下:

package com.example.administrator.animation_practice;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by Administrator on 2018/4/1 0001.
 * powered by Cpf.com.
 */
public class DragViewGroup extends FrameLayout {
    private ViewDragHelper mViewDragHelper;
    private View mMenuView, mMainView;
    private int mWidth;

    public DragViewGroup(Context context) {
        super(context);
        initView();
    }

    public DragViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }

    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = mMenuView.getMeasuredWidth();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将触摸事件传递给ViewDragHelper,此操作必不可少
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    private void initView() {
        mViewDragHelper = ViewDragHelper.create(this, callback);
    }

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

                // 何时开始检测触摸事件
                @Override
                public boolean tryCaptureView(View child, int pointerId) {
                    //如果当前触摸的child是mMainView时开始检测
                    return mMainView == child;
                }

                // 触摸到View后回调
                @Override
                public void onViewCaptured(View capturedChild,
                                           int activePointerId) {
                    super.onViewCaptured(capturedChild, activePointerId);
                }

                // 当拖拽状态改变,比如idle,dragging
                @Override
                public void onViewDragStateChanged(int state) {
                    super.onViewDragStateChanged(state);
                }

                // 当位置改变的时候调用,常用与滑动时更改scale等
                @Override
                public void onViewPositionChanged(View changedView,
                                                  int left, int top, int dx, int dy) {
                    super.onViewPositionChanged(changedView, left, top, dx, dy);
                }

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

                // 处理水平滑动
                @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) {
                        //关闭菜单
                        //相当于Scroller的startScroll方法
                        mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                        ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                    } else {
                        //打开菜单
                        mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
                        ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
                    }
                }
            };

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

ViewDragHelper类的使用,大概可以分为四步:每步的含义都很清晰

1)初始化ViewDragHelper类;

2)ViewGroup写入拦截事件,将事件传递给ViewDragHelper进行处理;

3)处理computeScroll,实现平滑移动;

4)处理回调Callback,决定滑动的子View是谁,同时处理回调Callback时,也要决定子View的滑动方向和写入回弹判断;

小结:在本例中,运行的代码较多,但实际,正如前文所讲的:“①自定义一个View,该View中有两个子View;②运用ViewDragHelper类实现自定义视图的滑动效果。”代码段也类似的可以分为两段:①自定义View段,对应代码行数15-50②操作ViewDragHelper类,对应代码行53-133

 本节内容是使用滑动效果最强大的ViewDragHelper类实现了一个仿QQ首页切换的效果,涉及到的内容较多,包括Android Scroll、自定义View和事件分发机制,感兴趣的读者可以参考下笔者之前的文章《View绘制流程—自定义View相关》《 Android事件分发机制精炼详解》,里面的相关讲解相信会解决读者的一些疑惑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值