C#完成向多線程傳參的三種方法實例剖析。本站提示廣大學習愛好者:(C#完成向多線程傳參的三種方法實例剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#完成向多線程傳參的三種方法實例剖析正文
在平凡的開辟中,我們常常會碰到點擊,滑動之類的事宜。有時刻分歧的view之間也存在各類滑動抵觸。好比結構的表裡兩層都能滑動的話,那末就會湧現抵觸了。這個時刻我們就須要懂得Android的事宜分發機制。
Android的觸摸事宜分發進程由三個很主要的辦法來配合完成:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。我先將這三個辦法年夜體的引見一下。
•public boolean dispatchTouchEvent(MotionEvent ev)
用來停止事宜的分發。假如事宜可以或許傳遞給以後View,那末此辦法必定會被挪用,前往成果受以後View的onTouchEvent和上級View的dispatchTouchEvent辦法的影響,表現能否消費以後事宜。ACTION_DOWN的dispatchTouchEvent()前往true,後續事宜(ACTION_MOVE、ACTION_UP)會再傳遞,假如前往false,dispatchTouchEvent()就吸收不到ACTION_UP、ACTION_MOVE。簡略的說,就是當dispatchTouchEvent在停止事宜分發的時刻,只要前一個action前往true,才會觸發後一個action。
•public boolean onInterceptTouchEvent(MotionEvent event)
這個辦法是在dispatchTouchEvent辦法中挪用的,用來攔阻某個事宜的。假如以後View攔阻了某個事宜,那末在統一個事宜序列中,此辦法不會被再次挪用,前往的成果表現能否攔阻以後事宜。它是ViewGroup供給的辦法,默許前往false。
•public boolean onTouchEvent(MotionEvent event)
在dispatchTouchEvent辦法中挪用,用來處置點擊事宜,前往成果表現能否消費失落以後事宜(true表現消費,false表現不用耗),假如不用耗,則在統一個事宜序列中,以後View沒法再次吸收到事宜。View和ViewGroup都有該辦法,View默許前往true,表現花費了這個事宜。
View裡,有兩個回調函數 :
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
ViewGroup裡,有三個回調函數 :
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
上述三個辦法中有甚麼差別和關系呢?上面用一段偽代碼表現:
public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if(onInterceptTouchEvent(ev)){ consume = onTouchEvent(ev); } else { consume = child.dispatchTouchEvent(ev); } return consume; }
經由過程下面的偽代碼年夜家能夠對點擊事宜的傳遞規矩有了更清晰的熟悉,即:關於一個根ViewGroup來講,點擊事宜發生後,起首會傳遞給它,這時候它的dispatchTouchEvent就會被挪用,假如這個ViewGroup的onInterceptTouchEvent辦法前往true表現它要攔阻此事宜,接著這個事宜就會交給這個ViewGroup處置,即它的onTouchEvent辦法就會被挪用;假如這個ViewGroup的onInterceptTouchEvent辦法前往false,就表現它不攔阻此事宜,這是以後事宜就會持續傳遞給它的子元素,接著子元素的dispatchTouchEvent辦法就會被挪用,如斯重復直到事宜被終究處置。
上面的幾張圖參考自[eoe]:
•圖一:ACTION_DOWN都沒被花費
•圖二(一):ACTION_DOWN被View花費了
•圖二(二):後續ACTION_MOVE和UP在不被攔阻的情形下都邑去找VIEW
•圖三:後續的被攔阻了
•圖四:ACTION_DOWN一開端就被攔阻
View事宜分起源碼剖析:
•dispatchTouchEvent辦法:
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != 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)辦法並前往。
總結上去onTouch可以或許獲得履行須要兩個條件前提(都知足):
1.設置了OnTouchListener
2.控件是enable狀況
而onTouchEvent可以或許獲得履行知足以下三個前提隨意率性一個便可:
1.沒有設置OnTouchListener
2.控件不是enable狀況
3.onTouch前往false
再來看一下dispatchTouchEvent的前往值,它其實受onTouch和onTouchEvent函數的前往值掌握,也就是說touch事宜被勝利花費前往true,它也就前往true,解釋分發勝利,爾後的事宜序列也會在此被分發,而假如前往false,則以為分發掉敗,爾後的事宜序列就不再分發下去了。
•onTouchEvent辦法:
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { ... return true; }
View的onTouchEvent默許都邑消費失落事宜(該辦法前往true),除非它是弗成點擊的(clickable和longClickable同時為false)。而且View的longClickable默許為false,clickable屬性要分情形,好比Button默許為true,TextView、ImageView默許為false。
public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; }
這不就是我們熟習的OnClickListener嗎,它本來是在onTouchEvent中被挪用的。只需mOnClickListener不是null,就會去挪用它的onClick辦法。
總結上去onClick可以或許獲得履行須要兩個條件前提(都知足):
1.可以履行到onTouchEvent
2.設置了OnClickListener
全部View的事宜轉發流程是:
dispatchEvent->setOnTouchListener->onTouchEvent->setOnClickListener
最初還有一個成績,setOnLongClickListener和setOnClickListener能否只能履行一個?
答:不是的,只需setOnLongClickListener中的onClick前往false,則兩個都邑履行;前往true則會屏障setOnClickListener。
ViewGroup事宜分起源碼剖析:
•dispatchTouchEvent辦法:
... if (disallowIntercept || !onInterceptTouchEvent(ev)) { ev.setAction(MotionEvent.ACTION_DOWN); final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { final float xc = scrolledXFloat - child.mLeft; final float yc = scrolledYFloat - child.mTop; ev.setLocation(xc, yc); child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; if (child.dispatchTouchEvent(ev)) { // Event handled, we have a target now. mMotionTarget = child; return true; } } } } }
兩種能夠會進入if代碼段(即事宜被分發給子View):
1、以後不許可攔阻,即disallowIntercept = true.
2、以後沒有攔阻,即onInterceptTouchEvent(ev)前往false.
注:disallowIntercept是指能否禁用失落事宜攔阻的功效,默許是false,可以經由過程ViewGroup.requestDisallowInterceptTouchEvent(boolean)停止設置;而onInterceptTouchEvent(ev)可以停止復寫。
進入if代碼段後,經由過程一個for輪回,遍歷以後ViewGroup下的一切子View,斷定以後遍歷的View是否是正在點擊的View,假如是的話就會挪用該View的dispatchTouchEvent,就進入了View的事宜分發流程了,下面有講。當child.dispatchTouchEvent(ev)前往true,則為mMotionTarget=child;然後return true,解釋ViewGroup的dispatchTouchEvent前往值受childView的dispatchTouchEvent前往值影響,子view事宜分發勝利,ViewGroup的事宜分發才勝利,爾後的事宜序列也會在此分發(從下面知:子view的clickable或longClickable為true都能分發勝利),而假如ViewGroup事宜分發掉敗或許沒有找到子View(點擊空白地位),則會走到它的onTouchEvent,今後的事宜序列也不會分發下去,直接走onTouchEvent。
全部ViewGroup的事宜轉發流程是:
dispatchEvent->onInterceptTouchEvent->child.dispatchEvent->(setOnTouchListener->onTouchEvent)
下面的總結都是基於:假如沒有攔阻;那末若何攔阻呢?
•onInterceptTouchEvent
public boolean onInterceptTouchEvent(MotionEvent ev) { return false; }
代碼很簡略,只要一句,即前往false,ViewGroup默許是不攔阻的。假如你須要攔阻,只需return true就好了,如許該事宜就不會往子View傳遞了,而且假如你在DOWN return true ,則DOWN,MOVE,UP子View都不會捕捉到事宜;假如你在MOVE return true , 則子View在MOVE和UP都不會捕捉到事宜。
若何不被攔阻:
假如ViewGroup的onInterceptTouchEvent(ev) 當ACTION_MOVE時return true ,即攔阻了子View的MOVE和UP事宜;此時子View願望仍然可以或許呼應MOVE和UP時該咋辦呢?
答:onInterceptTouchEvent是界說在ViewGroup中的,子View沒法修正。Android給我們供給了一個辦法:requestDisallowInterceptTouchEvent(boolean) 用於設置能否許可攔阻,我們在子View的dispatchTouchEvent中直接這麼寫:
@Override public boolean dispatchTouchEvent(MotionEvent event) { getParent().requestDisallowInterceptTouchEvent(true); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "dispatchTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "dispatchTouchEvent ACTION_UP"); break; default: break; } return super.dispatchTouchEvent(event); }
getParent().requestDisallowInterceptTouchEvent(true); 如許即便ViewGroup在MOVE的時刻return true,子View仍然可以捕捉到MOVE和UP事宜。
注:假如ViewGroup在onInterceptTouchEvent(ev) ACTION_DOWN外面直接return true了,那末子View是沒有方法的捕捉事宜的!
總結
關於代碼流程下面曾經總結過了~
1、假如ViewGroup找到了可以或許處置該事宜的View,則直接交給子View處置,本身的onTouchEvent不會被觸發;
2、可以經由過程復寫onInterceptTouchEvent(ev)辦法,攔阻子View的事宜(即return true),把事宜交給本身處置,則會履行本身對應的onTouchEvent辦法
3、子View可以經由過程挪用getParent().requestDisallowInterceptTouchEvent(true); 阻攔ViewGroup對其MOVE或許UP事宜停止攔阻;
好了,那末現實運用中能處理哪些成績呢?
好比你在ScrollView中嵌套了一個EditText,當EditText中文字內容太多超越規模時,你想高低滑動使EditText中文字轉動出來,卻發明轉動的是ScrollView。這時候我們設置EditText的onTouch事宜,在onTouch中設置不讓ScrollView攔阻我的事宜,最初在UP時把狀況改歸去。
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if ((view.getId() == R.id.tousuContentEditText && canVerticalScroll(tousuContentEditText))) { view.getParent().requestDisallowInterceptTouchEvent(true); if (motionEvent.getAction() == MotionEvent.ACTION_UP) { view.getParent().requestDisallowInterceptTouchEvent(false); } } return false; } private boolean canVerticalScroll(EditText editText) { int scrollY = editText.getScrollY(); int scrollRange = editText.getLayout().getHeight(); int scrollExtent = editText.getHeight() - editText.getCompoundPaddingTop() - editText.getCompoundPaddingBottom(); int scrollDifference = scrollRange - scrollExtent; if (scrollDifference == 0) { return false; } return (scrollY > 0) || (scrollY < scrollDifference - 1); }
以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。