您的位置:首页 > 移动开发 > Android开发

Android之View的TouchDelegate,你真的理解事件分发了吗???

2018-01-26 18:56 459 查看
有人问我 事件分发是分发给View的吗?

我笃定的说是的,结果不是的。

其实View有一个TouchDelegate,可以给他设置这样一个东西,来使得你的事件触摸范围会被增大!简直牛X!

这个类的全部源码及部分注释

public class TouchDelegate {

/**
* View that should receive forwarded touch events
*/
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;//给mBounds稍微扩大点,其目的是消除触摸误差

/**
* True if the delegate had been targeted on a down event (intersected mBounds).
*/
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) {//构造函数:rect是实际触摸区域,view是要修改触摸区域的view
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) {//这里是核心代码了:如果你落在这个rect区域内,就判定你是落在这个view内了,view自然就可以获取这次事件
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区域小来进行的一个防止误差,所以你触摸到了rect,不一定有效
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]

event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);//如果说是在rect区域内,那么就把event的位置修改在view的中心,模拟触摸事件是真的落在了view内了

} 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;
}
}


看看view是如何使用TouchDelegate的,在它的onTouchEvent里,首先就进行了一个判断

if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}


但是实战的时候,又发现不是这么一回事了,我的理解完全出现了偏差

其真正含义是,当你触摸一个view的时候,而且touch delegate的矩形区域也在这个view里,你触摸到了这块区域,那么这个view就可以把事件转发给delegate类中维护的那个view

实战演练



代码

重写了activity的onWindowFousChanged

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
TextView tv = (TextView) root.getChildAt(0);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "666", Toast.LENGTH_SHORT).show();
}
});

Rect rect = new Rect();
rect.top = tv.getTop() - 100;
rect.bottom = tv.getBottom() + 100;
rect.left = tv.getLeft() - 100;
rect.right = tv.getRight() + 100;

root.setTouchDelegate(new TouchDelegate(rect, tv));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: