缘起
我在处理事件分发机制相关的问题时,发现布局中子
view
分别为Button
和TextView
的时候,onInterceptTouchEvent
方法能接受的MotionEvent
不同,于是就去了解了下二者有何不同。
探寻
先看Button
的源码。
Button 这个类代码很少,继承自TextView。
除了getAccessibilityClassName
和 onResolvePointerIcon
这两个方法不同之外,构造方法也不同。这是是我关注的点。
public Button(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.buttonStyle);
}
可以说,Button
和 TextView
的区别就在于com.android.internal.R.attr.buttonStyle
。
找到 com.android.internal.R.attr.buttonStyle这个文件
看#125行。
<item name="buttonStyle">@style/Widget.Button</item>
然后找Widget.Button
,Widget.Button 345行
345 <style name="Widget.Button">
346 <item name="background">@drawable/btn_default</item>
347 <item name="focusable">true</item>
348 <item name="clickable">true</item>
349 <item name="textAppearance">?attr/textAppearanceSmallInverse</item>
350 <item name="textColor">@color/primary_text_light</item>
351 <item name="gravity">center_vertical|center_horizontal</item>
352 </style>
这里体现出来了二者不同。
- Button 有背景,点击,按下都有相应的效果。
- 可点击。
- 默认有焦点。
- 样式不同,比如颜色,位置等
clickable 在 事件分发机制的体现
public boolean onTouchEvent(MotionEvent event) {
//省略无关代码
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL
case MotionEvent.ACTION_MOVE:
}
return true;
}
return false;
}
可以看到,clickable == true
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP)
成立,最终返回 return true;
否则,返回false
可以看出,clickable
关系着onTouchEvent
的返回值,也就是当前View是否消费该事件。
参考
好好读读源码 button
Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
Android中View的Clickable和Enabled的区别与原理