快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

bet356亚洲版在线体育投注_酒文化网进入



从我的第一篇文章开始,就零琐屑散在很多多少地方应用到了Android事故分发的常识。也有很多多少同伙问过我各类问题,比如:onTouch和onTouchEvent有什么差别,又该若何应用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片应用Button而不用ImageView?等等……对付这些问题,我并没有给出异常具体的回答,由于我知道假如想要彻底搞明白这些问题,掌握Android事bet356亚洲版在线体育投注故分发机制是必弗成少的,而Android事故分发机制绝对不是一言半语就能说得清的。

今朝虽然网上相关的文章也不少,但我感觉没有哪篇写得分外具体的(大概我还没有找到),多半文章只是讲了讲理论,然后共同demo运行了一下结果。而我筹备带着大年夜家从源码的角度进行阐发,信托大年夜家可以加倍深刻地舆解Android事故分发机制。

涉猎源码考究由浅入深,循规蹈矩,是以我们也从简单的开始,本篇先带大年夜家商量View的事故分发,下篇再去商量难度更高的ViewGroup的事故分发。

那我们现在就开始吧!比如说你当前有一个异常简单的项目,只有一个Activity,并且Activity中只有一个按钮。你可能已经知道,假如想要给这个按钮注册一个点击事故,只必要调用:

button.setOnClickListener(new OnClickListener() {

@Overridepublic void onClick(View v) {

Log.d("TAG", "onClick execute");}

});

这样在onClick措施里面写实现,就可以在按钮被点击的时刻履行。你可能也已经知道,假如想给这个按钮再添加一个touch事故,只必要调用:

button.setOnTouchListener(new OnTouchListener() {

@Overridepublic boolean onTouch(View v, MotionEvent event) {

Log.d("TAG", "onTouch execute, action " + event.getAction());return false;

}});

onTouch措施里能做的工作比onClick要多一些,比如判断手指按下、抬起、移动等事故。那么假如我两个事故都注册了,哪一个会先履行呢?我们来试一下就知道了,运行法度榜样点击按钮,打印结果如下:

可以看到,onTouch是优先于onClick履行的,并且onTouch履行了两次,一次是ACTION_DOWN,一次是ACTION_UP(你还可能会有多次ACTION_MOVE的履行,假如你手抖了一下)。是以事故通报的顺序是先颠末onTouch,再通报到onClick。

细心的同伙应该可以留意到,onTouch措施是有返回值的,这里我们返回的是false,假如我们考试测验把onTouch措施里的返回值改成true,再运行一次,结果如下:

我们发明,onClick措施不再履行了!为什么会这样呢?你可以先理解成onTouch措施返回true就觉得这个事故被onTouch破费掉落了,因而不会再继承向下通报。

假如到现在为止,以上的所有常识点你都是清楚的,那么阐明你对Android事故通报的基础用法应该是掌握了。不过别满意于现状,让我们从源码的角度阐发一下,呈现上述征象的道理是什么。

首先你必要知道一点,只要你触摸到了任何一个控件,就必然会调用该控件的dispatchTouchEvent措施。那当我们去点击按钮的时刻,就会去调用Button类里的dispatchTouchEvent措施,可是你会发明Button类里并没有这个措施,那么就到它的父类TextView里去找一找,你会发明TextView里也没有这个措施,那没法子了,只好继承在TextView的父类View里找一找,这个时刻你终于在View里找到了这个措施,示意图如下:

然后我们来看一下View中dispatchTouchEvent措施的源码:

public boolean dispatchTouchEvent(MotionEvent event) {

if (mOnTouchListener != bet356亚洲版在线体育投注null && (mViewFlags & ENABLED_MASK) == ENABLED &&mOnTouchListener.onTouch(this, event)) {

return true;}

return onTouchEvent(event);}

这个措施异常的简洁,只有短短几行代码!我们可以看到,在这个措施内,首先是进行了一个判断,假如mOnTouchListener != null,(mViewFlags & ENABLED_MASK) == ENABLED和mOnTouchListener.onTouch(this, event)这三个前提都为真,就返回true,否则就去履行onTouchEvent(event)措施并返回。

先看一下第一个前提,mOnTouchListener这个变量是在哪里赋值的呢?我们探求之后在View里发清楚明了如下措施:

public void setOnTouchListener(OnTouchListener l) {

mOnTouchListener = l;}

Bingo!找到了,mOnTouchListener恰是在setOnTouchListener措施里赋值的,也便是说只要我们给控件注册了touch事故,mOnTouchListener就必然被赋值了。

第二个前提(mViewFlags & ENABLED_MASK) == ENABLED是判断当前点击的控件是否是enable的,按钮默认都是enable的,是以这个前提恒定为true。

第三个前提就对照关键了,mOnTouchListener.onTouch(this, event),着实也便是去回调控件注册touch事故时的onTouch措施。也便是说假如我们在onTouch措施里返回true,就会让这三个前提整个成立,从而全部措施直接返回true。假如我们在onTouch措施里返回false,就会再去履行onTouchEvent(event)措施。

现在我们可以结合前面的例子来阐发一下了,首先在dispatchTouchEvent中最先履行的便是onTouch措施,是以onTouch肯定是要优

先于onClick履行的,也是印证了刚刚的打印结果。而假如在onTouch措施里返回了true,就会让dispatchTouchEvent措施直接返回true,不会再继承往下履行。而打印结果也证明了假如onTouch返回true,onClick就不会再履行了。

根据以上源码的阐发,从道理上说清楚明了我们前面例子的运行结果。而上面的阐发回透漏出了一个紧张的信息,那便是onClick的调用肯定是在onTouchEvent(event)措施中的!那我们顿时来看下onTouchEvent的源码,如下所示:

public boolean onTouchEvent(MotionEvent event) {

final int viewFlags = mViewFlags;if ((viewFlags & ENABLED_MASK) == DISABLED) {

// A disabled view that is clickable still consumes the touch// events, it just doesn't respond to them.

Return (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));

}if (mTouchDelegate != null) {

if (mTouchDelegate.onTouchEvent(event)) {return true;

}}

if (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {

switch (event.getAction()) {case MotionEvent.ACTION_UP:

boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;if ((mPrivateFlags & PRESSED) != 0 || prepressed) {

// take focus if we don't have it already and we should in// touch mode.

Boolean focusTaken = false;if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {

focusTaken = requestFocus();}

if (!mHasPerformedLongPress) {// This is a tap, so remove the longpress check

removeLongPressCallback();// Only perform take click actions if we were in the pressed state

if (!focusTaken) {// Use a Runnable and post this rather than calling

// performClick directly. This lets other visual state// of the view update before click actions start.

If (mPerformClick == null) {mPerformClick = new PerformClick();

}if (!post(mPerformClick)) {

performClick();}

}}

if (mUnsetPressedState == null) {mUnsetPressedState = new UnsetPressedState();

}if (prepressed) {

mPrivateFlags |= PRESSED;refreshDrawableState();

postDelayed(mUnsetPressedState,ViewConfiguration.getPrebet356亚洲版在线体育投注ssedStateDuration());

} else if (!post(mUnsetPressedState)) {// If the post failed, unpress right now

mUnsetPressedState.run();}

removeTapCallback();}

break;case MotionEvent.ACTION_DOWN:

if (mPendingCheckForTap == null) {mPendingCheckForTap = new CheckForTap();

}mPrivateFlags |= PREPRESSED;

mHasPerformedLongPress = false;postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

break;case MotionEvent.ACTION_CANCEL:

mPrivateFlags &= ~PRESSED;refreshDrawableState();

removeTapCallback();break;

case MotionEvent.ACTION_MOVE:final int x = (int) event.getX();

final int y = (int) event.getY();// Be lenient about moving outside of buttons

int slop = mToucbet356亚洲版在线体育投注hSlop;if ((x 0 - slop) || (x >= getWidth() + slop) ||

(y 0 - slop) || (y >= getHeight() + slop)) {// Outside button

removeTapCallback();if ((mPrivateFlags & PRESSED) != 0) {

// Remove any future long press/tap checksremoveLongPressCallback();

// Need to switch from pressed to not pressedmPrivateFlags &= ~PRESSED;

refreshDrawableState();}

}break;

}return true;

}return false;

}

相较于刚才的dispatchTouchEvent措施,onTouchEvent措施繁杂了很多,不过不要紧,我们只挑重点看就可以了。

首先在第14行我们可以看出,假如该控件是可以点击的就会进入到第16行的switch判断中去,而假如当前的事故是抬起手指,则会进入到MotionEvent.ACTION_UP这个case傍边。在颠末各种判断之后,会履行到第38行的performClick()措施,那我们进入到这个措施里瞧一瞧:

public boolean performClick() {

sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);if (mOnClickListener != null) {

playSoundEffect(SoundEffectConstants.CLICK);mOnClickListener.onClick(this);

return true;}

return false;}

可以看到,只要mOnClickListener不是null,就会去调用它的onClick措施,那mOnClickListener又是在哪里赋值的呢?颠末探求后找到如下措施:

public void setOnClickListener(OnClickListener l) {

if (!isClickable()) {setClickable(true);

}mOnClickListener = l;

}

统统都是那么清楚了!当我们经由过程调用setOnClickListener措施来给控件注册一个点击事故时,就会给mOnClickListener赋值。然后每当控件被点击时,都邑在performClick()措施里回调被点击控件的onClick措施。

这样View的全部事故分发的流程就让我们搞清楚了!不过别痛快的太早,现在还没停止,还有一个很紧张的常识点必要阐明,便是touch事故的层级通报。我们都知道假如给一个控件注册了touch事故,每次点击它的时刻都邑触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事故。这里必要留意,假如你在履行ACTION_DOWN的时刻返回了false,后面一系列其它的action就不会再获得履行了。简单的说,便是当dispatchTouchEvent在进行事故分发的时刻,只有前一个action返回true,才会触发后一个action。

说到这里,很多的同伙肯定要有伟大年夜的疑问了。这不是在自相抵触吗?前面的例子中,明明在onTouch事故里面返回了false,ACTION_DOWN和ACTION_UP不是都获得履行了吗?着实你只是被假象所迷惑了,让我们仔细阐发一下,在前面的例子傍边,我们到底返回的是什么。

参考着我们前面阐发的源码,首先在onTouch事故里返回了false,就必然会进入到onTouchEvent措施中,然后我们来看一下onTouchEvent措施的细节。因为我们点击了按钮,就会进入到第14行这个if判断的内部,然后你会发明,不管当前的action是什么,终极都必然会走到第89行,返回一个true。

是不是有一种被诈骗的感到?明明在onTouch事故里返回了false,系统照样在onTouchEvent措施中帮你返回了true。就由于这个缘故原由,才使得前面的例子中ACTION_UP可以获得履行。

那我们可以换一个控件,将按钮调换成ImageView,然后给它也注册一个touch事故,并返回false。如下所示:

imageView.setOnTouchListener(new OnTouchListener() {

@Overridepublic boolean onTouch(View v, MotionEvent event) {

Log.d("TAG", "onTouch execute, action " + event.getAction());return false;

}});

运行一下法度榜样,点击ImageView,你会发明结果如下:

在ACTION_DOWN履行完后,后面的一系列action都不会获得履行了。这又是为什么呢?由于ImageView和按钮不合,它是默认弗成点击的,是以在onTouchEvent的第14行判断时无法进入到if的内部,直接跳到第91行返回了false,也就导致后面其它的action都无法履行了。

好了,关于View的事故分发,我想讲的器械全都在这里了。现在我们再往返首一下开篇时提到的那三个问题,信托每小我都邑有更深一层的理解。

1. onTouch和onTouchEvent有什么差别,又该若何应用?

从源码中可以看出,这两个措施都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent履行。假如在onTouch措施中经由过程返回true将事故破费掉落,onTouchEvent将不会再履行。

别的必要留意的是,onTouch能够获得履行必要两个条件前提,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。是以假如你有一个控件长短enable的,那么给它注册onTouch事故将永世得不到履行。对付这一类控件,假如我们想要监听它的touch事故bet356亚洲版在线体育投注,就必须经由过程在该控件中重写onTouchEvent措施来实现。

2. 为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?

假如你涉猎了http://www.fengfly.com/plus/view-215084-1.html 这篇文章,你应该会知道滑动菜单的功能是经由过程给ListView注册了一个touch变糊弄实现的。假如你在onTouch措施里处置惩罚完了滑动逻辑后返回true,那么ListView本身的滚动事故就被樊篱了,自然也就无法滑动(道理同前面例子中按钮不能点击),是以办理法子便是在onTouch措施里返回false。

3. 为什么图片轮播器里的图片应用Button而不用ImageView?

提这个问题的同伙是看过了http://www.fengfly.com/plus/view-215085-1.html 这篇文章。当时我在图片轮播器里应用Button,主要便是由于Button是可点击的,而ImageView是弗成点击的。假如想要应用ImageView,可以有两种改法。第一,在ImageView的onTouch措施里返回true,这样可以包管ACTION_DOWN之后的其它action都能获得履行,才能实现图片滚动的效果。第二,在结构文件里面给ImageView增添一个android:clickable="true"的属性,这样ImageView变成可点击的之后,纵然在onTouch里返回了false,ACTION_DOWN之后的其它action也是可以获得履行的。

本日的解说就到这里了,信托大年夜家现在对Android事故分发机制又有了进一步的熟识,在后面的文章中我会再带大年夜家一路商量Android中ViewGroup的事故分发机制,感兴趣的同伙请继承涉猎下一篇文章。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: