做Android开发的人都用过Selector,可以方便的实现View在不同状态下的背景。不过,相信大部分开发者遇到过和我一样的问题,本文会从源码角度,解释这些问题。
首先,这里简单描述一下,我遇到的问题:
界面上有个全屏的LinearLayout A,A中有一个TextView B和Button C,其中,A的clickable=true,并设置了pressed时,背景色为灰色,B设置了pressed时,背景色为蓝色当手指触摸C下方的空白区域时,看到了这样的效果:
在这里看到,在没有触摸B的情况下,B的pressed = true,而C的pressed = false。 C的状态暂且不讨论,按照Android消息传递的原则,因为touch的point不在B内部,所以,touch消息应该不会交给B处理,那为什么B的pressed = true?
下面开始一步一步分析(本文分析的Android源码为4.2.2)。
Pressed状态的设定
从View.onTouchEvent函数看起(frameworks/base/core/java/android/view/View.java):
/**
* Implement this method to handle touch screen motion events.
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
......
if (((viewFlags & CLICKABLE) == CLICKABLE || //这里是为什么设置A的clickable为true的原因,否则,press A的时候,没有界面元素处理touch event,最终会由Activity的onTouchEvent函数处理
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
......
break;
case MotionEvent.ACTION_DOWN:
mHasPerformedLongPress = false;
......
// Walk up the hierarchy to determine if we're inside a scrolling container.
boolean isInScrollingContainer = isInScrollingContainer();//A已经是顶层元素了,没有ScrollView之类的控件存在,所以,isInScrollingContainer = false
// For views inside a scrolling container, delay the pressed feedback for
// a short period in case this is a scroll.
if (isInScrollingContainer) {
mPrivateFlags |= PFLAG_PREPRESSED;
if (mPendingCheckForTap == null) {