Android事件分发07——TouchDelegate的使用与解析
2017-04-24 11:00
375 查看
Android事件分发07TouchDelegate的使用与解析
一TouchDelegate的简单使用
1 图示
2 activity_touch_delegate_demoxml
2 TouchDelegateDemoActivity
二TouchDelegate源码
三主要的小小分析
1 构造函数
2 MotionEventACTION_DOWN
3 MotionEventACTION_MOVE和MotionEventACTION_UP
4 MotionEventACTION_CANCEL
5 余下的处理
四流程图
判断有没有添加TouchDelegate代理,如果添加了代理,那么调用代理的onTouchEvent方法处理,如果这个方法返回true,那么就返回true,代表消费了事件,如果没有返回true,那么继续其他处理。
mBounds这个使我们按下时候判断的区域
mSlopBounds这个是我们移动时候判断的区域
按下的时候,判断当前的点是不是落在我们的区域内,如果是,那么我们标记我们的初始值。
判断有没有代理,有代理,点超出了范围,那么设置
根据前面的动作处理以后的标记判断,时候需要代理来处理消息,如果需要返回false,,如果需要我们判断,点是否已经超出了触摸范围,更改点的位置,调用代理view的事件分发。
一TouchDelegate的简单使用
1 图示
2 activity_touch_delegate_demoxml
2 TouchDelegateDemoActivity
二TouchDelegate源码
三主要的小小分析
1 构造函数
2 MotionEventACTION_DOWN
3 MotionEventACTION_MOVE和MotionEventACTION_UP
4 MotionEventACTION_CANCEL
5 余下的处理
四流程图
Android事件分发07——TouchDelegate的使用与解析
TouchDelegate 这个类的作用就是增大我们控件的触摸区域。前面文章(Android事件分发05——View的onTouchEvent)中,我们在分析 onTouchEvent的时候,有个步骤是这样的:判断有没有添加TouchDelegate代理,如果添加了代理,那么调用代理的onTouchEvent方法处理,如果这个方法返回true,那么就返回true,代表消费了事件,如果没有返回true,那么继续其他处理。
public boolean onTouchEvent(MotionEvent event) { ... if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } ... }
一、TouchDelegate的简单使用
我们通过下面的小小例子来演示了TouchDelegate的简单使用。1.1 图示
这里面我们实现的东西很简单,就是增大触摸区域:如图1.2 activity_touch_delegate_demo.xml
activity_touch_delegate_demo.xml<?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.support.v7.widget.AppCompatButton android:textAllCaps="false" android:layout_centerInParent="true" android:id="@+id/test_btn" android:text="TouchDelegate测试" android:layout_width="200dp" android:layout_height="60dp" /> </RelativeLayout>
1.2 TouchDelegateDemoActivity
TouchDelegateDemoActivitypublic class TouchDelegateDemoActivity extends BaseActivity { private AppCompatButton testBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_touch_delegate_demo); testBtn = (AppCompatButton)findViewById(R.id.test_btn); testBtn.setOnClickListener(mOnClickListener); View parent = (View) testBtn.getParent(); parent.post(new Runnable() { @Override public void run() { int offset = 200; Rect rect = new Rect(); testBtn.getHitRect(rect); rect.set(rect.left-offset, rect.top-offset, rect.right+offset, rect.bottom+offset); TouchDelegate delegate = new TouchDelegate(rect,testBtn); ((View)testBtn.getParent()).setTouchDelegate(delegate); } }); } private View.OnClickListener mOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(TouchDelegateDemoActivity.this, "测试而已", Toast.LENGTH_SHORT).show(); } }; }
二、TouchDelegate源码
public class TouchDelegate { /** * View that should receive forwarded touch events * 代理的view */ private View mDelegateView; /** * Bounds in local coordinates of the containing view that should be mapped to the delegate * view. This rect is used for initial hit testing. * 触摸区域 */ private Rect mBounds; /** * mBounds inflated to include some slop. This rect is to track whether the motion events * should be considered to be be within the delegate view. * 移动时候触摸区域,包含了误差 */ private Rect mSlopBounds; /** * True if the delegate had been targeted on a down event (intersected mBounds). * 标记 down 事件,是否落在了触摸区域内 */ private boolean mDelegateTargeted; /** * The touchable region of the View extends above its actual extent. */ public static final int ABOVE = 1; /** * The touchable region of the View extends below its actual extent. */ public static final int BELOW = 2; /** * The touchable region of the View extends to the left of its * actual extent. */ public static final int TO_LEFT = 4; /** * The touchable region of the View extends to the right of its * actual extent. */ public static final int TO_RIGHT = 8; private int mSlop; /** * Constructor * * @param bounds Bounds in local coordinates of the containing view that should be mapped to * the delegate view * @param delegateView The view that should receive motion events */ public TouchDelegate(Rect bounds, View delegateView) { mBounds = bounds; //获取相对的触摸区域的误差值(就是在这个超过原来的触摸区域,只要超出值小于等于这个值,都算在触摸区域内) mSlop = ViewConfiguration.get(delegateView.getContext()).getScaledTouchSlop(); mSlopBounds = new Rect(bounds); mSlopBounds.inset(-mSlop, -mSlop); mDelegateView = delegateView; } /** * Will forward touch events to the delegate view if the event is within the bounds * specified in the constructor. * * @param event The touch event to forward * @return True if the event was forwarded to the delegate, false otherwise. */ public boolean onTouchEvent(MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); boolean sendToDelegate = false; boolean hit = true; boolean handled = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Rect bounds = mBounds; //判断这个区域包含不包含这个点 if (bounds.contains(x, y)) { mDelegateTargeted = true; sendToDelegate = true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: sendToDelegate = mDelegateTargeted; if (sendToDelegate) { Rect slopBounds = mSlopBounds; //判断移动的点是否超出了范围 if (!slopBounds.contains(x, y)) { hit = false; } } break; case MotionEvent.ACTION_CANCEL: sendToDelegate = mDelegateTargeted; mDelegateTargeted = false; break; } if (sendToDelegate) { final View delegateView = mDelegateView; //判断移动的点是否没有超出了我们的范围 if (hit) { // Offset event coordinates to be inside the target view //没有超出,重新设置触摸的点,以确保我们下面调用代理的view的分发方法时,控件能够判断点是落在它上面的 event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2); } else { // Offset event coordinates to be outside the target view (in case it does // something like tracking pressed state) int slop = mSlop; //超出了,重新设置触摸的点,保证控件能判断点不是落在它上面 event.setLocation(-(slop * 2), -(slop * 2)); } handled = delegateView.dispatchTouchEvent(event); } return handled; } }
三、主要的小小分析
主要说明一下,TouchDelegate的原理,其实很简单,就是:事件传递到我们的代理中来的时候,我们的判断点有木有落在我们指定的区域内,如果落在区域内,那么我们把点修改为控件中间的点(这样可以确保此控件为最合适的view),如果点不在区域内,那么我们修改点击的点(这样可以确保此控件不是最合适的view),通过判断要不要分发动作,如果需要那么我们就用代理的view来分发事件。3.1 构造函数
首先来看看 60–67行:这里面是构造函数初始化部分public TouchDelegate(Rect bounds, View delegateView) { mBounds = bounds; //获取相对的触摸区域的误差值(就是在这个超过原来的触摸区域,只要超出值小于等于这个值,都算在触摸区域内) mSlop = ViewConfiguration.get(delegateView.getContext()).getScaledTouchSlop(); mSlopBounds = new Rect(bounds); mSlopBounds.inset(-mSlop, -mSlop); mDelegateView = delegateView; }
mBounds这个使我们按下时候判断的区域
mSlopBounds这个是我们移动时候判断的区域
3.2 MotionEvent.ACTION_DOWN
case MotionEvent.ACTION_DOWN: Rect bounds = mBounds; //判断这个区域包含不包含这个点 if (bounds.contains(x, y)) { //如果点在区域内,那么标记我们有代理 mDelegateTargeted = true; //标记需要发送处理到代理 sendToDelegate = true; } break;
按下的时候,判断当前的点是不是落在我们的区域内,如果是,那么我们标记我们的初始值。
3.3 MotionEvent.ACTION_MOVE和MotionEvent.ACTION_UP
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: sendToDelegate = mDelegateTargeted; if (sendToDelegate) {//有代理 Rect slopBounds = mSlopBounds; //判断移动的点是否超出了范围 if (!slopBounds.contains(x, y)) { hit = false; } } break;
判断有没有代理,有代理,点超出了范围,那么设置
hit = false;。
3.4 MotionEvent.ACTION_CANCEL
case MotionEvent.ACTION_CANCEL: //修改状态 sendToDelegate = mDelegateTargeted; mDelegateTargeted = false;
3.5 余下的处理
if (sendToDelegate) { final View delegateView = mDelegateView; //判断移动的点是否没有超出了我们的范围 if (hit) { // Offset event coordinates to be inside the target view //没有超出,重新设置触摸的点,以确保我们下面调用代理的view的分发方法时,控件能够判断点是落在它上面的 event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2); } else { // Offset event coordinates to be outside the target view (in case it does // something like tracking pressed state) int slop = mSlop; //超出了,重新设置触摸的点,保证控件能判断点不是落在它上面 event.setLocation(-(slop * 2), -(slop * 2)); } handled = delegateView.dispatchTouchEvent(event); }
根据前面的动作处理以后的标记判断,时候需要代理来处理消息,如果需要返回false,,如果需要我们判断,点是否已经超出了触摸范围,更改点的位置,调用代理view的事件分发。
四、流程图
相关文章推荐
- Android事件分发08——TouchDelegate的使用的一个示例与问题分析
- Android 源码解析View的touch事件分发机制
- Android中Touch事件分发过程全解析
- Android之View的TouchDelegate,你真的理解事件分发了吗???
- Android 中与 Touch 事件分发解析
- Android的touch事件分发的源码解析
- Android事件分发机制完全解析,带你从源码的角度彻底理解dispatchTouchEvent,onInterceptTouchEvent
- Android源码解析ViewGroup的touch事件分发机制
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- 【Android】Touch事件分发
- Android View 事件分发机制 源码解析
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- 深入源码理解Android Touch事件分发机制(下篇)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android之事件分发机制深入理解与详细解析(ViewGroup)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android 编程下 Touch 事件的分发和消费机制
- Android事件分发、View事件Listener全解析