摘要:當不攔截事件的時候,事件會向下分發(fā)交由它的子或進行處理。表示以及分發(fā)給其中在內(nèi)部完成被賦值。會自己處理事件。
目錄介紹
01.Android中事件分發(fā)順序
02.Activity的事件分發(fā)機制
2.1 源碼分析
2.2 點擊事件調(diào)用順序
2.3 得出結(jié)論
03.ViewGroup事件的分發(fā)機制
3.1 看一下這個案例
3.2 源碼分析
3.3 得出結(jié)論
04.View事件的分發(fā)機制
4.1 源碼分析
4.2 得出結(jié)論
4.3 驗證結(jié)論
05.思考一下
5.1 onTouch()和onTouchEvent()的區(qū)別
5.2 Touch事件的后續(xù)事件傳遞
好消息博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識點,Android技術(shù)博客,Python學習筆記等等,還包括平時開發(fā)中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續(xù)完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計N篇[近100萬字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請注明出處,謝謝!
鏈接地址:https://github.com/yangchong2...
如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!
View事件系列博客
01.View事件基礎(chǔ)
事件分發(fā)的對象是誰?事件在哪些對象間進行傳遞?事件分發(fā)過程涉及方法?事件分發(fā)機制方法說明?
02.View事件分發(fā)場景
事件分發(fā)背景描述,事件傳遞情況
03.View事件機制源碼分析
Android中事件分發(fā)順序?Activity的事件分發(fā)機制?ViewGroup事件的分發(fā)機制 ?View事件的分發(fā)機制?onTouch()和onTouchEvent()的區(qū)別?
04.View事件機制
觸摸事件,分發(fā)事件,攔截事件,三個事件機制怎么向其調(diào)用者傳遞處理結(jié)果,滑動沖突的思路及方法 ,以及具體的滑動沖突解決方案案例
05.View的滑動沖突
通過一個滑動沖突的案例,來講解外部攔截法解決滑動沖突,內(nèi)部攔截法解決滑動沖突
07.View事件總結(jié)1
Android事件分發(fā)機制,View和ViewGroup分發(fā)事件,onTouch()、onTouchEvent()和onClick()執(zhí)行順序,View處理事件的優(yōu)先級,點擊事件傳遞過程,事件傳遞規(guī)則要點
08.View事件總結(jié)2
View滑動有哪些方法,Activity事件分發(fā)過程,Window事件分發(fā)過程,DecorView的事件分發(fā),根View的事件分發(fā)
01.Android中事件分發(fā)順序
Android中事件分發(fā)順序:
Activity(Window) -> ViewGroup -> View
其中:
super:調(diào)用父類方法
true:消費事件,即事件不繼續(xù)往下傳遞
false:不消費事件,事件繼續(xù)往下傳遞 / 交由給父控件onTouchEvent()處理
充分理解Android分發(fā)機制,本質(zhì)上是要理解:
Activity對點擊事件的分發(fā)機制
ViewGroup對點擊事件的分發(fā)機制
View對點擊事件的分發(fā)機制
02.Activity的事件分發(fā)機制 2.1 源碼分析
當一個點擊事件發(fā)生時,事件最先傳到Activity的dispatchTouchEvent()進行事件分發(fā)
具體是由Activity的Window來完成
我們來看下Activity的dispatchTouchEvent()的源碼
public boolean dispatchTouchEvent(MotionEvent ev) { //第一步 //一般事件列開始都是DOWN,所以這里基本是true if (ev.getAction() == MotionEvent.ACTION_DOWN) { //第二步 onUserInteraction(); } //第三步 if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }
第一步
一般事件列開始都是DOWN(按下按鈕),所以這里返回true,執(zhí)行onUserInteraction()
第二步
先來看下onUserInteraction()源碼
public void onUserInteraction() { }
從源碼可以看出:
該方法為空方法
從注釋得知:當此activity在棧頂時,觸屏點擊按home,back,menu鍵等都會觸發(fā)此方法
所以onUserInteraction()主要用于屏保
第三步
Window類是抽象類,且PhoneWindow是Window類的唯一實現(xiàn)類
superDispatchTouchEvent(ev)是抽象方法
通過PhoneWindow類中看一下superDispatchTouchEvent()的作用
@Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); //mDecor是DecorView的實例 //DecorView是視圖的頂層view,繼承自FrameLayout,是所有界面的父類 }
接下來我們看mDecor.superDispatchTouchEvent(event):
public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); //DecorView繼承自FrameLayout //那么它的父類就是ViewGroup 而super.dispatchTouchEvent(event)方法,其實就應該是ViewGroup的dispatchTouchEvent() }
得出結(jié)果
執(zhí)行g(shù)etWindow().superDispatchTouchEvent(ev)實際上是執(zhí)行了ViewGroup.dispatchTouchEvent(event)
這樣事件就從 Activity 傳遞到了 ViewGroup
2.2 點擊事件調(diào)用順序
當一個點擊事件發(fā)生時,調(diào)用順序如下
1.事件最先傳到Activity的dispatchTouchEvent()進行事件分發(fā)
2.調(diào)用Window類實現(xiàn)類PhoneWindow的superDispatchTouchEvent()
3.調(diào)用DecorView的superDispatchTouchEvent()
4.最終調(diào)用DecorView父類的dispatchTouchEvent(),即ViewGroup的dispatchTouchEvent()
2.3 得出結(jié)論當一個點擊事件發(fā)生時,事件最先傳到Activity的dispatchTouchEvent()進行事件分發(fā),最終是調(diào)用了ViewGroup的dispatchTouchEvent()方法
這樣事件就從 Activity 傳遞到了 ViewGroup
03.ViewGroup事件的分發(fā)機制 3.1 看一下這個案例
布局如下:
結(jié)果測試
只點擊Button,發(fā)現(xiàn)執(zhí)行順序:btn1,btn2
再點擊空白處,發(fā)現(xiàn)執(zhí)行順序:btn1,btn2,viewGroup
從上面的測試結(jié)果發(fā)現(xiàn):
當點擊Button時,執(zhí)行Button的onClick(),但ViewGroupLayout注冊的onTouch()不會執(zhí)行
只有點擊空白區(qū)域時才會執(zhí)行ViewGroupLayout的onTouch();
結(jié)論:Button的onClick()將事件消費掉了,因此事件不會再繼續(xù)向下傳遞。
3.2 源碼分析
ViewGroup的dispatchTouchEvent()源碼分析,該方法比較復雜,截取幾個重要的邏輯片段進行介紹,來解析整個分發(fā)流程。
// 發(fā)生ACTION_DOWN事件或者已經(jīng)發(fā)生過ACTION_DOWN,并且將mFirstTouchTarget賦值,才進入此區(qū)域,主要功能是攔截器 final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) { //disallowIntercept:是否禁用事件攔截的功能(默認是false),即不禁用 //可以在子View通過調(diào)用requestDisallowInterceptTouchEvent方法對這個值進行修改,不讓該View攔截事件 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; //默認情況下會進入該方法 if (!disallowIntercept) { //調(diào)用攔截方法 intercepted = onInterceptTouchEvent(ev); ev.setAction(action); } else { intercepted = false; } } else { // 當沒有觸摸targets,且不是down事件時,開始持續(xù)攔截觸摸。 intercepted = true; }
這一段的內(nèi)容主要是為判斷是否攔截。如果當前事件的MotionEvent.ACTION_DOWN,則進入判斷,調(diào)用ViewGroup onInterceptTouchEvent()方法的值,判斷是否攔截。如果mFirstTouchTarget != null,即已經(jīng)發(fā)生過MotionEvent.ACTION_DOWN,并且該事件已經(jīng)有ViewGroup的子View進行處理了,那么也進入判斷,調(diào)用ViewGroup onInterceptTouchEvent()方法的值,判斷是否攔截。如果不是以上兩種情況,即已經(jīng)是MOVE或UP事件了,并且之前的事件沒有對象進行處理,則設(shè)置成true,開始攔截接下來的所有事件。這也就解釋了如果子View的onTouchEvent()方法返回false,那么接下來的一些列事件都不會交給他處理。如果VieGroup的onInterceptTouchEvent()第一次執(zhí)行為true,則mFirstTouchTarget = null,則也會使得接下來不會調(diào)用onInterceptTouchEvent(),直接將攔截設(shè)置為true。
當ViewGroup不攔截事件的時候,事件會向下分發(fā)交由它的子View或ViewGroup進行處理。
/* 從最底層的父視圖開始遍歷, ** 找尋newTouchTarget,即上面的mFirstTouchTarget ** 如果已經(jīng)存在找尋newTouchTarget,說明正在接收觸摸事件,則跳出循環(huán)。 */ for (int i = childrenCount - 1; i >= 0; i--) { final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex); // 如果當前視圖無法獲取用戶焦點,則跳過本次循環(huán) if (childWithAccessibilityFocus != null) { if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; } //如果view不可見,或者觸摸的坐標點不在view的范圍內(nèi),則跳過本次循環(huán) if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { ev.setTargetAccessibilityFocus(false); continue; } newTouchTarget = getTouchTarget(child); // 已經(jīng)開始接收觸摸事件,并退出整個循環(huán)。 if (newTouchTarget != null) { newTouchTarget.pointerIdBits |= idBitsToAssign; break; } //重置取消或抬起標志位 //如果觸摸位置在child的區(qū)域內(nèi),則把事件分發(fā)給子View或ViewGroup if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // 獲取TouchDown的時間點 mLastTouchDownTime = ev.getDownTime(); // 獲取TouchDown的Index if (preorderedList != null) { for (int j = 0; j < childrenCount; j++) { if (children[childIndex] == mChildren[j]) { mLastTouchDownIndex = j; break; } } } else { mLastTouchDownIndex = childIndex; } //獲取TouchDown的x,y坐標 mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); //添加TouchTarget,則mFirstTouchTarget != null。 newTouchTarget = addTouchTarget(child, idBitsToAssign); //表示以及分發(fā)給NewTouchTarget alreadyDispatchedToNewTouchTarget = true; break; }
dispatchTransformedTouchEvent()方法實際就是調(diào)用子元素的dispatchTouchEvent()方法。
其中dispatchTransformedTouchEvent()方法的重要邏輯如下:
if (child == null) { handled = super.dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); }
由于其中傳遞的child不為空,所以就會調(diào)用子元素的dispatchTouchEvent()。如果子元素的dispatchTouchEvent()方法返回true,那么mFirstTouchTarget就會被賦值,同時跳出for循環(huán)。
//添加TouchTarget,則mFirstTouchTarget != null。 newTouchTarget = addTouchTarget(child, idBitsToAssign); //表示以及分發(fā)給NewTouchTarget alreadyDispatchedToNewTouchTarget = true;
其中在addTouchTarget(child, idBitsToAssign);內(nèi)部完成mFirstTouchTarget被賦值。如果mFirstTouchTarget為空,將會讓ViewGroup默認攔截所有操作。如果遍歷所有子View或ViewGroup,都沒有消費事件。ViewGroup會自己處理事件。
3.3 得出結(jié)論Android事件分發(fā)是先傳遞到ViewGroup,再由ViewGroup傳遞到View
在ViewGroup中通過onInterceptTouchEvent()對事件傳遞進行攔截
1.onInterceptTouchEvent方法返回true代表攔截事件,即不允許事件繼續(xù)向子View傳遞;
2.返回false代表不攔截事件,即允許事件繼續(xù)向子View傳遞;(默認返回false)
3.子View中如果將傳遞的事件消費掉,ViewGroup中將無法接收到任何事件。
04.View事件的分發(fā)機制 4.1 源碼分析
View中dispatchTouchEvent()的源碼分析
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
從上面可以看出:
只有以下三個條件都為真,dispatchTouchEvent()才返回true;否則執(zhí)行onTouchEvent(event)方法
第一個條件:mOnTouchListener != null; 第二個條件:(mViewFlags & ENABLED_MASK) == ENABLED; 第三個條件:mOnTouchListener.onTouch(this, event);
下面,我們來看看下這三個判斷條件:
第一個條件:mOnTouchListener!= null
//mOnTouchListener是在View類下setOnTouchListener方法里賦值的 public void setOnTouchListener(OnTouchListener l) { //即只要我們給控件注冊了Touch事件,mOnTouchListener就一定被賦值(不為空) mOnTouchListener = l; }
第二個條件:(mViewFlags & ENABLED_MASK) == ENABLED
該條件是判斷當前點擊的控件是否enable
由于很多View默認是enable的,因此該條件恒定為true
第三個條件:mOnTouchListener.onTouch(this, event)
回調(diào)控件注冊Touch事件時的onTouch方法
//手動調(diào)用設(shè)置 button.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return false; } });
如果在onTouch方法返回true,就會讓上述三個條件全部成立,從而整個方法直接返回true。
如果在onTouch方法里返回false,就會去執(zhí)行onTouchEvent(event)方法。
接下來,我們繼續(xù)看:onTouchEvent(event)的源碼分析
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; } } //如果該控件是可以點擊的就會進入到下兩行的switch判斷中去; if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { //如果當前的事件是抬起手指,則會進入到MotionEvent.ACTION_UP這個case當中。 switch (event.getAction()) { case MotionEvent.ACTION_UP: boolean prepressed = (mPrivateFlags & PREPRESSED) != 0; // 在經(jīng)過種種判斷之后,會執(zhí)行到關(guān)注點1的performClick()方法。 //請往下看關(guān)注點1 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)) { //關(guān)注點1 //請往下看performClick()的源碼分析 performClick(); } } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (prepressed) { mPrivateFlags |= PRESSED; refreshDrawableState(); postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } 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 = mTouchSlop; 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 checks removeLongPressCallback(); // Need to switch from pressed to not pressed mPrivateFlags &= ~PRESSED; refreshDrawableState(); } } break; } //如果該控件是可以點擊的,就一定會返回true return true; } //如果該控件是不可以點擊的,就一定會返回false return false; }
關(guān)注點1:
performClick()的源碼分析
public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; }
只要mOnClickListener不為null,就會去調(diào)用onClick方法;
那么,mOnClickListener又是在哪里賦值的呢?請繼續(xù)看:
public void setOnClickListener(OnClickListener l) { if (!isClickable()) { setClickable(true); } mOnClickListener = l; }
當我們通過調(diào)用setOnClickListener方法來給控件注冊一個點擊事件時,就會給mOnClickListener賦值(不為空),即會回調(diào)onClick()。
4.2 得出結(jié)論1.onTouch()的執(zhí)行高于onClick()
2.每當控件被點擊時:
如果在回調(diào)onTouch()里返回false,就會讓dispatchTouchEvent方法返回false,那么就會執(zhí)行onTouchEvent();如果回調(diào)了setOnClickListener()來給控件注冊點擊事件的話,最后會在performClick()方法里回調(diào)onClick()。
onTouch()返回false(該事件沒被onTouch()消費掉) = 執(zhí)行onTouchEvent() = 執(zhí)行OnClick()
如果在回調(diào)onTouch()里返回true,就會讓dispatchTouchEvent方法返回true,那么將不會執(zhí)行onTouchEvent(),即onClick()也不會執(zhí)行;
onTouch()返回true(該事件被onTouch()消費掉) = dispatchTouchEvent()返回true(不會再繼續(xù)向下傳遞) = 不會執(zhí)行onTouchEvent() = 不會執(zhí)行OnClick()
4.3 驗證結(jié)論
在回調(diào)onTouch()里返回true
TextView textView = findViewById(R.id.tv_13); //設(shè)置OnTouchListener() textView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("小楊逗比","執(zhí)行了onTouch(), 動作是:" + event.getAction()); return true; } }); //設(shè)置OnClickListener textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("小楊逗比","執(zhí)行了onClick()"); } });
打印日志如下所示
注意action為0是ACTION_DOWN,為2是ACTION_MOVE,為1是ACTION_UP。
2019-04-04 13:37:58.301 13616-13616/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:0 2019-04-04 13:37:58.315 13616-13616/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:2 2019-04-04 13:37:58.405 13616-13616/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:2 2019-04-04 13:37:58.408 13616-13616/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:1
在回調(diào)onTouch()里返回false
打印結(jié)果如下所示
2019-04-04 13:41:26.961 14006-14006/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:0 2019-04-04 13:41:26.978 14006-14006/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:2 2019-04-04 13:41:27.072 14006-14006/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:2 2019-04-04 13:41:27.074 14006-14006/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onTouch(), 動作是:1 2019-04-04 13:41:27.076 14006-14006/org.yczbj.ycrefreshview D/小楊逗比: 執(zhí)行了onClick()
總結(jié):onTouch()返回true就認為該事件被onTouch()消費掉,因而不會再繼續(xù)向下傳遞,即不會執(zhí)行OnClick()。
05.思考一下 5.1 onTouch()和onTouchEvent()的區(qū)別這兩個方法都是在View的dispatchTouchEvent中調(diào)用,但onTouch優(yōu)先于onTouchEvent執(zhí)行。
如果在onTouch方法中返回true將事件消費掉,onTouchEvent()將不會再執(zhí)行。
特別注意:請看下面代碼
//&&為短路與,即如果前面條件為false,將不再往下執(zhí)行 //所以,onTouch能夠得到執(zhí)行需要兩個前提條件: //1. mOnTouchListener的值不能為空 //2. 當前點擊的控件必須是enable的。 mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)
因此如果你有一個控件是非enable的,那么給它注冊onTouch事件將永遠得不到執(zhí)行。對于這一類控件,如果我們想要監(jiān)聽它的touch事件,就必須通過在該控件中重寫onTouchEvent方法來實現(xiàn)。
5.2 Touch事件的后續(xù)事件(MOVE、UP)層級傳遞如果給控件注冊了Touch事件,每次點擊都會觸發(fā)一系列action事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP等)
當dispatchTouchEvent在進行事件分發(fā)的時候,只有前一個事件(如ACTION_DOWN)返回true,才會收到后一個事件(ACTION_MOVE和ACTION_UP)
即如果在執(zhí)行ACTION_DOWN時返回false,后面一系列的ACTION_MOVE和ACTION_UP事件都不會執(zhí)行
從上面對事件分發(fā)機制分析知:
dispatchTouchEvent()和 onTouchEvent()消費事件、終結(jié)事件傳遞(返回true)
而onInterceptTouchEvent 并不能消費事件,它相當于是一個分叉口起到分流導流的作用,對后續(xù)的ACTION_MOVE和ACTION_UP事件接收起到非常大的作用
請記?。航邮樟薃CTION_DOWN事件的函數(shù)不一定能收到后續(xù)事件(ACTION_MOVE、ACTION_UP)
這里給出ACTION_MOVE和ACTION_UP事件的傳遞結(jié)論:
如果在某個對象(Activity、ViewGroup、View)的dispatchTouchEvent()消費事件(返回true),那么收到ACTION_DOWN的函數(shù)也能收到ACTION_MOVE和ACTION_UP
如果在某個對象(Activity、ViewGroup、View)的onTouchEvent()消費事件(返回true),那么ACTION_MOVE和ACTION_UP的事件從上往下傳到這個View后就不再往下傳遞了,而直接傳給自己的onTouchEvent()并結(jié)束本次事件傳遞過程。
其他介紹 01.關(guān)于博客匯總鏈接1.技術(shù)博客匯總
2.開源項目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡書:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽書:http://www.ximalaya.com/zhubo...
開源中國:https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77846.html
摘要:注意,事件分發(fā)是向下傳遞的,也就是父到子的順序。事件分發(fā)機制的本質(zhì)是要解決,點擊事件由哪個對象發(fā)出,經(jīng)過哪些對象,最終達到哪個對象并最終得到處理。表示以及分發(fā)給其中在內(nèi)部完成被賦值。會自己處理事件。 目錄介紹 01.Android中事件分發(fā)順序 1.1 事件分發(fā)的對象是誰 1.2 事件分發(fā)的本質(zhì) 1.3 事件在哪些對象間進行傳遞 1.4 事件分發(fā)過程涉及方法 1.5 Androi...
摘要:在代碼中的直接應用是或者是。就像一個控制器,統(tǒng)籌視圖的添加與顯示,以及通過其他回調(diào)方法,來與以及進行交互。創(chuàng)建需要通過創(chuàng)建,通過將加載其中,并將交給,進行視圖繪制以及其他交互。創(chuàng)建機制分析實例的創(chuàng)建中執(zhí)行,從而生成了的實例。 目錄介紹 01.Window,View,子Window 02.什么是Activity 03.什么是Window 04.什么是DecorView 05.什么是Vi...
閱讀 2473·2021-11-24 09:39
閱讀 3405·2021-11-15 11:37
閱讀 2250·2021-10-08 10:04
閱讀 3965·2021-09-09 11:54
閱讀 1882·2021-08-18 10:24
閱讀 1032·2019-08-30 11:02
閱讀 1792·2019-08-29 18:45
閱讀 1651·2019-08-29 16:33