Buttonクリック時にスライドするイベント転送
4014 ワード
背景
前の面接でスライドに関する質問があったので、とても難解でしたが、後で関連資料とソースコードを調べてやっと解決できました.質問はRecyclerViewの中でitemがButtonで、このButtonを押しながらスライドすれば、Buttonは焦点を保つことができますか?関連イベントはどのように伝達されますか?
考える
従来のイベント伝達メカニズムの理解では、DownイベントViewGroup->Buttonを押してスライドすると一連のMoveイベントであったが、上向きのMoveイベントがViewGroup(RecyclerView)にブロックされるため、Buttonは焦点を失い、実験結果も同様であったが、ViewGroupが本当にMove以降のすべてのイベントをブロックすると、Buttonはどのようにして自分がフォーカスを失ったことを知って、UIをフォーカスを失ったUIに更新します(少なくとも1つのCANCELまたはUPイベントを取得しなければなりませんか?).Moveがブロックされた後にCANCELイベントを受信したことが実験で証明されたが、このCANCELはどのように来たのだろうか.
ソース解析
ViewGroupのdispatchTouchEventメソッドの最後の部分には、このようなコードがあります.
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
大まかな流れは、イベントがchild処理に渡されたかどうかを判断し、返された場合、そうでなければdispatchTransformedTouchEventを介してchildにCANCELイベントを渡すことを試みる.一部のコードは以下の通りである.
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
// Canceling motions is a special case. We don't need to perform any transformations
// or filtering. The important part is the action, not the contents.
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
...
}
ここでchildにCANCELイベントを伝えていることがわかります