Android事件分发机制的神秘面纱

今天看了鸿神他的博文之后有点感触,对就像他们所说事件分发这东西不是一二句话就能解释明白的,真正要了解他们的内部机制怎样运行还是需要去研究源码,因为那里基本可以找到答案

首先看下效果

这里写图片描述

然后看下log日志根据你的拖拽看他是向上还是向左移动

这里写图片描述

这里写图片描述

这个方法比较重要

创建实例需要3个参数,第一个就是当前的ViewGroup,第二个sensitivity,主要用于设置touchSlop:

源码可以看到

 public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
        final ViewDragHelper helper = create(forParent, cb);
        helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
        return helper;
    }

再看下面ViewDragHelper创建时会调用create方法,然后获取一个实例那么允许VDH使用不同的内部兼容性实现不同的平台

 /**
     * Apps should use ViewDragHelper.create() to get a new instance.
     * This will allow VDH to use internal compatibility implementations for different
     * platform versions.
     *
     * @param context Context to initialize config-dependent params from
     * @param forParent Parent view to monitor
     */
    private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
        if (forParent == null) {
            throw new IllegalArgumentException("Parent view may not be null");
        }
        if (cb == null) {
            throw new IllegalArgumentException("Callback may not be null");
        }

        mParentView = forParent;
        mCallback = cb;

        final ViewConfiguration vc = ViewConfiguration.get(context);
        final float density = context.getResources().getDisplayMetrics().density;
        mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);

        mTouchSlop = vc.getScaledTouchSlop();
        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
        mMinVelocity = vc.getScaledMinimumFlingVelocity();
        mScroller = ScrollerCompat.create(context, sInterpolator);
    }

然后介绍一下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是一个用于编写自定义ViewGroups的实用程序类。它提供了一个数字
*用于允许用户拖动和重新定位的有用操作和状态跟踪
*在其父ViewGroup中的视图这下集合上面的效果图相信大家应该不陌生了!

public static final int EDGE_LEFT = 1 << 0;
表明左边缘应受影响。
 public static final int EDGE_RIGHT = 1 << 1;
表明右边缘应受影响。
 public static final int EDGE_TOP = 1 << 2;
 表明顶部边缘应受影响。
 public static final int EDGE_BOTTOM = 1 << 3;
 表明 底部边缘受影响

public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;
这个表示上下左右边缘都会受影响

**
     * Edge flag indicating that the left edge should be affected.
     */


    /**
     * Edge flag indicating that the right edge should be affected.
     */


    /**
     * Edge flag indicating that the top edge should be affected.
     */
    public static final int EDGE_TOP = 1 << 2;

    /**
     * Edge flag indicating that the bottom edge should be affected.
     */
    public static final int EDGE_BOTTOM = 1 << 3;

    /**
     * Edge flag set indicating all edges should be affected.
     */
    public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;

下面再看下CallBack

/**
     * A Callback is used as a communication channel with the ViewDragHelper back to the
     * parent view using it. <code>on*</code>methods are invoked on siginficant events and several
     * accessor methods are expected to provide the ViewDragHelper with more information
     * about the state of the parent view upon request. The callback also makes decisions
     * governing the range and draggability of child views.
     */
    public abstract static class Callback {
        /**
         * Called when the drag state changes. See the <code>STATE_*</code> constants
         * for more information.
         *
         * @param state The new drag state
         *
         * @see #STATE_IDLE
         * @see #STATE_DRAGGING
         * @see #STATE_SETTLING
         */

回调用作具有ViewDragHelper的通信通道,父视图使用它的方法在siginficant事件和几个方法上被调访问器方法应该为ViewDragHelper提供更多信息关于请求时父视图的状态。回调等
释放

            /**
             * 释放的时候自动自动弹回
             * @param releasedChild
             * @param xvel
             * @param yvel
             */
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                super.onViewReleased(releasedChild, xvel, yvel);
                if(releasedChild==mAutoBackView)
                {
                    mDragger.settleCapturedViewAt(mAutoBackOriginPosition.x,mAutoBackOriginPosition.y);
                }
                //边界检测
                mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
            }

禁止拖拽
onLayout之后保存了最开启的位置信息,最主要还是重写Callback中的onViewReleased,我们在onViewReleased中判断如果是mAutoBackView则调用settleCapturedViewAt回到初始的位置。大家可以看到紧随其后的代码是invalidate();方法因为其内部使用的是mScroller.startScroll,所以别忘了需要invalidate()以及结合computeScroll方法一起。

 @Override
            public boolean tryCaptureView(View child, int pointerId) {
                //mEdgeTrackerView禁止直接移动
                return child == mDragView || child == mEdgeTrackerView;
            }

效果如下

这里写图片描述

最后上全部代码

package zm.jc.com.bmobsys.dialog;

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

/**
 * Created by John on 2017/1/13.
 */

public class MyLayout extends LinearLayout {
    private ViewDragHelper mDragger;//v4包
    private static final String TAG = "MyLayout";
    public MyLayout(Context context) {
        super(context);
    }

    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDragger= ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return true;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
//                final int leftBound=getPaddingLeft();
//                final int rightBound=getWidth()-  mDragger.getWidth() - leftBound;
//                final int newLeft=Math.min(Math.max(left.leftBound),rightBound);
                Log.d(TAG, "clampViewPositionHorizontal: left ");
                return left;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                Log.d(TAG, "clampViewPositionHorizontal: top ");
                return top;
            }
        });

    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event)
    {
        return mDragger.shouldInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragger.processTouchEvent(event);
        return true;
    }
}

转载请注明出处,同时希望大家狠批我的博客,谢谢哈哈!写的不好的地方直接下面留下您的足迹我会去一一回复的哈哈!
疯狂Android进阶之旅

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值