前に書かれています:
Android 開発者として、多くの人がインタビュー中に次の 2 つの質問に遭遇したことがあります: 1. よく知っているデザイン パターンについて話す; 2. Android のタッチ イベント分散メカニズム。この記事では、一連の責任パターンを設計パターンに組み合わせて、Android タッチ イベントの配布をシミュレートします。
1. 責任モデルの連鎖
責任の連鎖モデルとは、簡単に言うと、複数の責任者が連鎖的につながったもので、現在の責任者にイベントが配信され、現在の責任者が対応しなければ、次のノードに引き継がれるというものです。誰もそれを処理しないまで責任者. それは、私たちが通常「ボールを蹴る」と言うようなものです. 責任の連鎖の主な機能は、責任の連鎖の各責任者が職務を遂行できるように、送信者と受信者を切り離すことです。「連鎖」といえば、その構造は実はデータ構造の連結リストに非常に似ており、一般的に言えば、一方通行の責任連鎖であれば、現在の責任者が次の責任者の参照を保持することができます。 . 双方向の責任連鎖である場合、現在のノードは、前後の責任者への参照を保持します。
2.イベント配信
ユーザーのタッチ イベントがディスパッチされ、現在のアクティビティから消費されます。デフォルトでは、アクティビティはイベントを消費せず、アクティビティはそれが接続されているウィンドウに渡され、ウィンドウは superDispatchTouchEvent() を介してルート ビューに渡されます。 onCreate() の始まり。一般的に言えば、ルート ビューは ViewGroup です。ViewGroup はデフォルトではイベントを消費しませんが、イベントをインターセプトする方法がもう 1 つあります。デフォルトでは、イベントをインターセプトせず、処理のために次のレベルのビューに引き渡します。ViewGroup が必要な場合現在のイベントを処理するには、onInterceptTouchEvent() メソッドを書き換えて true を返し、それを ViewGroup の onTouchEvent メソッドに渡して処理します。イベントは通常、ビューに渡されるときに処理され、クリック イベント、長押しイベントなどになります。ビューが消費しない場合、タッチ イベントは元のパスに沿って戻ります。したがって、大規模なプロセスで言えば、イベントの配信メカニズムは、Activity -> Window -> View (広義には、ViewGroup とそのサブビューを含む) であり、このイベント配信モデルの観点からは、実際には 2 つのイベント配信モデルです。 - 責任の連鎖。実際、Android のイベント配信では、一連の責任パターンが使用されています。(質問の差し引きを開始)
3. 武魂融合術 - コードを見せて
最初に責任者の基本クラスを作成します。各責任者はこの基本クラスを継承して実装します。物事を単純化するために、Activity をシミュレートしてそのウィンドウとルート View を見つけるプロセスを省略し、Activity から ViewGroup、サブ View へのイベントの配布プロセスをシミュレートします。各責任者には、責任の連鎖で各責任者を接続するための分散メソッドがあります。
abstract class AbsTouch {
var next:AbsTouch?=null//下一责任人
var previous:AbsTouch?=null//上一责任人
private var isDispatched=false//是否从上一责任人转发下来过
//事件分发主要方法
open fun dispatch(event: String){
val onTouch = onTouch(event)//具体事件处理
//事件被处理则责任链结束,不再向上或向下传递
if (onTouch){
println("$event 事件被处理")
return
}
//事件第一次来且不是责任链最后一位责任人,向下传递
if (!isDispatched&&next!=null){
println("懒得处理,给下一位 $event")
isDispatched=true
next?.dispatch(event)
}else{
//事件不是第一次来或者是责任链最后一位责任人,向上回传
println("懒得处理,给上一位 $event")
previous?.dispatch(event)
}
}
//具体决定是否消费触摸事件
abstract fun onTouch(event: String):Boolean
}
Activity、ViewGroup、View の 3 人の責任者をシミュレートする 3 つのクラスを実装します。アクティビティには onTouchEvent メソッドしかありません
class Activity : AbsTouch(){
val TAG=Activity::class.simpleName
override fun onTouch(event: String): Boolean {
println("$TAG:$event 来啦")
//activity默认不处理,返回false
return false
}
}
ViewGroup には、イベントをインターセプトするための onInterceptTouchEvent メソッドがもう 1 つあります。
open class ViewGroup : AbsTouch(){
val TAG=ViewGroup::class.simpleName
//ViewGroup是否消费先决条件为是否拦截,不拦截直接转发
//拦截的话传给onTouchEvent
override fun dispatch(event: String) {
if (onIntercept())
onTouch(event)
else super.dispatch(event)
}
override fun onTouch(event: String): Boolean {
println("$TAG:$event 来啦")
return false
}
//相较于Activity和View ,ViewGroup多了一个onInterceptTouchEvent()方法
//且默认不拦截
open fun onIntercept():Boolean{
return false
}
}
また、View には onTouchEvent メソッドが 1 つしかありません。デフォルトでは true を返します = イベントを消費します。
class View : AbsTouch(){
val TAG=View::class.simpleName
var clickAbel=true
//view的onTouchEvent默认返回true
//当用户自定义为false或设置clickable=false时,view不消费事件
override fun onTouch(event: String): Boolean {
println("$TAG:$event 来啦")
return clickAbel
}
}
3 人の責任者をインスタンス化し、それらの間の関係を責任の連鎖に確立します。イベントはアクティビティから開始され、デフォルトの ViewGroup は状況をインターセプトしません
@Test
fun onClick(){
val activity= Activity()
val viewGroup = ViewGroup()
activity.next=viewGroup
viewGroup.previous=activity
val view = View()
viewGroup.next=view
view.previous=viewGroup
activity.dispatch("点击事件")
}
イベント配信結果は以下の通り
イベントをインターセプトする ViewGroup のメソッドを書き換え、責任の連鎖で ViewGroup を置き換えます. イベントがインターセプトされると、イベントはこの ViewGroup によって処理され、転送されません.
class NewViewGroup:ViewGroup() {
override fun onIntercept(): Boolean {
return true
}
}
現時点でのイベント配信結果は以下の通りです。
処理しない場合、イベント配信プロセスは次のようになります。
、
裏面に次のように書きます。
1.責任モデルは実際には非常に単純です.主なことは、基本クラスがチェーン上の隣接ノードへの参照を保持し、ビジネスロジックに従って分散メソッドを実装することです. 利用シーンもいろいろありますが、ここでのイベント配信以外にも、一般的なokhttpインターセプターもこのデザインパターンを採用しています。
2. イベント配信 3 つの主な役割は、Activity、Window、View です。
3 つの主要なアプローチ
dispatchTouchEvent: チェーン上の隣接するノードに接続して、イベントを配布します。
onInterceptTouchEvent: ViewGroup に固有で、イベントをインターセプトし、インターセプト後にその onTouchEvent に直接移動します。
onTouchEvent: イベントを処理するかどうか、およびそれらを処理する方法。
実装例とは異なり、クリック イベントは単一のイベントではなく一連のイベント ストリームであることが多く、担当者が最初の ACTION_DOWN メソッドを処理しないことを選択した場合、それがもたらす後続のイベント ストリームはビューによって処理されません。この記事では、一般的な観点から一般的なプロセスについて説明します. 言及されていない詳細については、このグラフィック Android イベント配信メカニズム、または他の書籍や資料を参照できます. 表現に誤りがありましたら、訂正をお願いします。