1.ネストされたスライドとは
ネストされたスライドは、Android開発で一般的なUI効果です。レイアウトに複数のスライド可能なビューが含まれていて、これらのビューが互いにネストされている場合、UIの相互作用に天井効果などのスムーズな効果を持たせるには、ネストされたスライド処理を実行する必要があります。一般的な効果は次のとおりです。
上に示したように、最も外側の親レイアウトはスライドでき、内側のRecyclerViewもスライドできます。RecyclerViewを上にスライドすると、最初に最も外側の親レイアウトがタブに到達するまで上にスライドします。このとき、RecyclerViewはスライドを開始し、親レイアウトはスライドを停止し、指が画面から離れる必要がないため、操作全体が実行されます。一度に完了することができます。このようにして、内部および外部レイアウトの連続スライドの効果が達成され、タブ天井の効果が達成されます。
2つのスライディングネスティングソリューション
では、どうすればこのようなコヒーレントなネストされたスライドを実現できるでしょうか。
1.イベントの配布と傍受を手動でオーバーライドします
誰もがAndroidのイベント配信メカニズムに精通しています。ネストされたスライドの効果を実現するには、イベント配信の書き換えが最も原始的な方法です。初期のAndroid開発者はこれを行いました。前に示した効果を例として取り上げます。ACTION_MOVEイベントが配布される場合、最初にタブの位置が上にあるかどうかを判断します。そうでない場合は、外側の親レイアウトがMOVEイベントをインターセプトし、親レイアウトがスライドします。すでに到着している場合は、イベントをインターセプトして子RecyclerViewに渡さないでください。プロセスは次のとおりです。
onIntercetTouchEvent
メソッドをオーバーライドするイベントをインターセプトするかどうかは、プロセスの中心です。
イベント配布を手動で書き換えるデメリット
-
比較的単純なネストされたスライド状況にのみ適しています
これは理解しやすいです。インターセプトロジックは自分で手動で作成する必要があるため、ネストされたスライディングのレイアウトが複雑になると、ネストされたスライディングを実装するために多くのコードとロジックが必要になり、メンテナンスのコストが増加します。したがって、複雑なネストされたスライディングレイアウトには適さず、複雑なネストされたスライディングを実現することは実際には困難です。
-
フリングをサポートするのは難しい
フリングとは、スライドが解除された後、ビューが慣性によってスライドし続けるプロセスを指します。一般的に、ユーザーエクスペリエンスを考慮すると、ネストされたスライドはフリングをサポートする必要があります。したがって、手動のイベント配布の準備のために、さらに書き直す
onInterceptTouchEvent
必要がありますが、ACTION_UP
フリングACTION_UP
によって生成されたイベントのために、特定の処理イベントの必要性もありますVelocity
。ただし、イベント配布メカニズムはonInterceptTouchEvent
、開発者がACITON_UP
イベントを処理できるようにする外部インターフェイスへのそのような公開を提供しません。onTouchEvent
他のメソッドを処理するためのレプリケーションのみを使用しますが、を呼び出す必要があるため、制限が厳しすぎsuper.onTouchEvent
ますが、コードを変更することはできません。 -
コヒーレントな天井ネスティングスライディングを実現する方法はありません
前の例をもう一度見てみましょう。タブが上にある場合、指が離さず、上にスライドしてRecyclerViewを上にスライドさせます。ただし、イベントを手動でインターセプトすることはできません。持ち上げる必要があります。最初に指を動かしてから、もう一度スライドさせます。なんでこんなことが起こっているの?
dispatchTouchEvent
コードを見てください:if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { ...... } else { // 当 MotionEvent 为 ACTION_MOVE 且 mFirstTouchTarget == null 时,仍然拦截事件 intercepted = true; }
配布ViewGroupイベントの場合
mFirstTouchTarget == null
、それがコンシューマーイベントへのサブViewGroupビューがないことを示している場合、これはViewGroup自身によって処理されます。そして、ViewGroupがイベントをインターセプトすると、はmFirstTouchTarget
空になります。前の例に戻ると、ACTION_MOVE
イベント後に外側のスライドレイアウトの父親がインターセプトすると、mFirstTouchTarget
空白になります。次に、mFirstTouchTarget
すでにのnull
ように、上限の後でさえイベントをインターセプトしないでください。そうすれば、イベントは子RecyclerViewに渡されませんが、親レイアウトによって引き続き消費されます。このように、天井の入れ子の連続的なスライド効果は達成されません。
2、CoordinatorLayout + AppBar + Behavior + scrollFlag
CoordinatorLayout
複雑な相互作用効果は、Googleのレイアウトによって提供さ達成することができているAppBar
、Behavior
、scrollFlag
デカップリングの使用が行われ、さまざまな効果をカスタマイズすることができますとBehavior
してscrollFlag
指定します。そしてBehavior
、カスタマイズすることができます。
使用して、CoordinatorLayout
ネストされたスライドは限りレイアウトファイルの準備は次のようにのように、非常に簡単です実装します。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_height="300dp"
android:layout_width="match_parent">
// 可滑动部分
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:layout_scrollFlags="scroll"/>
<TextView
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_gravity="bottom"
android:text="Top"
android:textSize="32sp"
android:textColor="@color/white"
android:gravity="center"
android:textStyle="bold"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
AppBarLayout
スライド部を隠すために必要scrollFlag
として指定されscroll
RecyclerViewに指定がbehavior
ありappbar_scrolling_view_behavior
、次のように最も簡単な天井ネストされたスライドは、達成することができます。
ヘッダー付きのRecyclerViewがスライドしているように見えますが、実際にはネストされたスライドです。
layout_scrollFlags
そしてlayout_behavior
、スライドネストに限らず、さまざまな効果を実現できる多くの可能な値があります。詳細については、APIドキュメントを参照してください。
CoordinatorLayout
入れ子を使用すると、手動でスライドするよりもはるかに優れた方法で実現できます。入れ子になった天井をスライドさせると、一貫性が得られますが、フリングもサポートされます。そして、それは公式のレイアウトであり、自信を持って使用でき、バグの可能性は非常に低く、パフォーマンスに問題はありません。しかし、それは公式が非常にうまくカプセル化されているからこそ、CoordinatorLayout
マルチレベルのネストされたスライドなど、より複雑なネストされたスライドレイアウトを実現するのは困難です。
3.ネストされたスライドコンポーネントNestedScrollingParentおよびNestedScrollingChild
NestedScrollingParent
そしてNestedScrollingChild
、スライド可能にネストされたコンポーネントに設計されたセットを解決するための公式グーグルです。これらは2つのインターフェースであり、コードは次のとおりです。
public interface NestedScrollingParent2 extends NestedScrollingParent {
boolean onStartNestedScroll(@NonNull View child, @NonNull View target, @ScrollAxis int axes,
@NestedScrollType int type);
void onNestedScrollAccepted(@NonNull View child, @NonNull View target, @ScrollAxis int axes,
@NestedScrollType int type);
void onStopNestedScroll(@NonNull View target, @NestedScrollType int type);
void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed, @NestedScrollType int type);
void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
@NestedScrollType int type);
}
public interface NestedScrollingChild2 extends NestedScrollingChild {
boolean startNestedScroll(@ScrollAxis int axes, @NestedScrollType int type);
void stopNestedScroll(@NestedScrollType int type);
boolean hasNestedScrollingParent(@NestedScrollType int type);
boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow,
@NestedScrollType int type);
boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow, @NestedScrollType int type);
}
ネストされたスライドを必要とするビューは、これら2つのインターフェースを実装し、それらのメソッドを書き直すことができます。ネストされたスライドを実現するためのこの一連のコンポーネントの基本原則は非常に単純で、主に次の3つのステップがあります。
NestedScrollingChild
に渡すことによって生成されonTouchEvent
た最初のACITON_MOVE
変位dxおよびdyイベントの方法でdispatchNestedPreScroll
はNestedScrollingParent
NestedScrollingParent
でonNestedPreScroll
受信したDXとDYと消費。変位に消費int[] consumed
、consumed
アレイは2のint型の長さの配列であり、consumed[0]
x軸消費の代表、consumed[1]
y軸消費の代表NestedScrollingChild
int[] consumed
get後、配列NestedScrollingParent
が消費された変位、残りの変位を差し引いた後に取得され、その後、独自の消費によって取得されます
スライド変位の伝達方向は、下図のように子→親→子からです。子がRecyclerviewの場合、最初に変位を親レイアウトに転送して消費し、次に親レイアウトをスライドさせます。親レイアウトがスライドできないところまでスライドすると、この時点でRecyclerviewがすべてのディスプレイスメントを消費します。このとき、Recyclerviewは自動的にスライドを開始し、ネストされたスライドを形成します。効果は前の例のようになります。
dispatchNestedScroll
そして、onNestedScroll
行動原理上のpreScroll、しかし、2枚のネストされたスライドとpreScroll逆順を構築するこの方法のように、消費者は、ビューの子は、親ビューの消費によって再び時間を消費し、することはできません、最初の子ビューです。
このメカニズムは、指がビューを離れるACITON_UP
ときに、イベント、この時点で子Velocity
が変位dx
またはdy
フローの前に流れて繰り返されるときに生成されるフリングもサポートします。@NestedScrollType int type
判定値TYPE_TOUCH
やTYPE_NON_TOUCH
、TYPE_TOUCH
スライド可能で、TYPE_NON_TOUCH
投げつけるています。
Androidのどのビューがこのスライドメカニズムを使用していますか?
NestedScrollingParent
インターフェイスの実装ビューNestedScrollView
は次のとおりです:CoordinatorLayout
、MotionLayout
など。NestedScrollingChild
インターフェイスの実装ビューNestedScrollView
は次のとおりですRecyclerView
。NestedScrollView
これは、2つのインターフェイスを同時に実装する唯一のビューです。つまり、後で説明するマルチレベルのネストされたスライドを実装するための仲介として使用できます。
上記からわかるように、実際には、CoordinatorLayout
ネストされたスライドが実装される前に述べましたが、これは基本的にこのNestedScrollingインターフェイスによって実現されます。しかし、パッケージが非常に優れているため、あまりカスタマイズすることはできません。また、この一連のインターフェイスを直接使用して、必要に応じてカスタマイズできます。
ほとんどのシーンではNestedScrollingChild
、インターフェイスを実装する必要はありません。これは、RecyclerViewがこれを実現するために行われており、ネストされたサブスライドシーンビューも必須のRecyclerViewであるためです。RecyclerViewの関連するソースコードを見てみましょう。
public boolean onTouchEvent(MotionEvent e) {
...
case MotionEvent.ACTION_MOVE: {
...
// 计算 dx,dy
int dx = mLastTouchX - x;
int dy = mLastTouchY - y;
...
mReusableIntPair[0] = 0;
mReusableIntPair[1] = 0;
...
// 分发 preScroll
if (dispatchNestedPreScroll(
canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
mReusableIntPair, mScrollOffset, TYPE_TOUCH
)) {
// 减去父 view 消费掉的位移
dx -= mReusableIntPair[0];
dy -= mReusableIntPair[1];
mNestedOffsets[0] += mScrollOffset[0];
mNestedOffsets[1] += mScrollOffset[1];
getParent().requestDisallowInterceptTouchEvent(true);
}
...
} break;
...
}
boolean scrollByInternal(int x, int y, MotionEvent ev) {
int unconsumedX = 0;
int unconsumedY = 0;
int consumedX = 0;
int consumedY = 0;
if (mAdapter != null) {
mReusableIntPair[0] = 0;
mReusableIntPair[1] = 0;
// 先消耗掉自己的 scroll
scrollStep(x, y, mReusableIntPair);
consumedX = mReusableIntPair[0];
consumedY = mReusableIntPair[1];
// 计算剩余的量
unconsumedX = x - consumedX;
unconsumedY = y - consumedY;
}
mReusableIntPair[0] = 0;
mReusableIntPair[1] = 0;
// 分发 nestedScroll 给父 View,顺序和 preScroll 刚好相反
dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset,
TYPE_TOUCH, mReusableIntPair);
unconsumedX -= mReusableIntPair[0];
unconsumedY -= mReusableIntPair[1];
...
}
RecyclerViewはどのように親ビューに転送し、さonNestedPreSroll
とonNestedScroll
それ?dispatchNestedPreScroll
以下のコードを分析してください。dispatchNestedScroll
原則とコードは類似しており、投稿されていません。
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow,
int type) {
return getScrollingChildHelper().dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow,type);
}
// NestedScrollingChildHelper.java
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow, @NestedScrollType int type) {
if (isNestedScrollingEnabled()) {
final ViewParent parent = getNestedScrollingParentForType(type);
if (parent == null) {
return false;
}
if (dx != 0 || dy != 0) {
...
consumed[0] = 0;
consumed[1] = 0;
ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
...
}
...
}
return false;
}
// ViewCompat.java
public static void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
int[] consumed, int type) {
if (parent instanceof NestedScrollingParent2) {
// First try the NestedScrollingParent2 API
((NestedScrollingParent2) parent).onNestedPreScroll(target, dx, dy, consumed, type);
} else if (type == ViewCompat.TYPE_TOUCH) {
// Else if the type is the default (touch), try the NestedScrollingParent API
if (Build.VERSION.SDK_INT >= 21) {
try {
parent.onNestedPreScroll(target, dx, dy, consumed);
} catch (AbstractMethodError e) {
Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ "method onNestedPreScroll", e);
}
} else if (parent instanceof NestedScrollingParent) {
((NestedScrollingParent) parent).onNestedPreScroll(target, dx, dy, consumed);
}
}
}
ご覧のとおり、プロキシクラスのNestedScrollingChildHelper
スライディング配布によるRecyclerViewが完了しました。これViewCompat
は、親ビューを作成するための静的な処理方法の最後onNestedPreScroll
です。ViewCompat
主な機能は、さまざまなバージョンのスライディングインターフェイスと互換性があることです。
onNestedPreScrollメソッドを実装します
上記のコードから、NestedScrollingChild
ネストされたスライドとトリガーのタイミングを実装するためのRecyclerViewを明確に見ることができます。ネストされたスライドを実現し、子ビュー内のスライドがRecyclerViewである場合NestedScrollingParent
は、onNestedPreScroll
メソッド内など、親ビュー実装メソッドの外層を行に配置します。
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
// 滑动 dy 距离
scrollBy(0, dy);
// 将消耗掉的 dy 放入 consumed 数组通知子 view
consumed[1] = dy;
}
これにより、最も単純なネストされたスライドが実現されます。もちろん、実際の状況では、スライド距離を判断する必要があり、親ビューが子ビューの変位を常に消費するとは限りません。
NestedScrollViewについて
同じようにNestedScrollView
、それが内部に実装しているため、このクラスonNestedScroll
の外には、あなたの指を持ち上げることなく、減少し続けるまで、その秋に、それはリストの上部の内側にRecyclerViewに落ちました。実現onNestedPreScroll
方法もありますが、次のコードでは、消費ではなく、転送プロセスで上にスライドし続けます。
// NestedScrollView.java
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
int type) {
// 只分发了 preScroll 自己并没有消费。之所以能分发是因为 NestedScrollView 同时实现了 NestedScrollingChild 接口
dispatchNestedPreScroll(dx, dy, consumed, null, type);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow,
int type) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
}
// NestedScrollingChildHelper.java
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow, @NestedScrollType int type) {
if (isNestedScrollingEnabled()) {
final ViewParent parent = getNestedScrollingParentForType(type);
if (parent == null) {
return false;
}
if (dx != 0 || dy != 0) {
...
consumed[0] = 0;
consumed[1] = 0;
ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
...
}
...
}
return false;
}
したがって、直接RecyclerViewアウタージャケットNestedScrollView
が完全なネストされたスライドを実現する方法ではない場合、滑りやすい場合はネストされたスライド効果はありませんが、ネストされたスライド効果がある場合は落ちます。
考慮されていない問題
実際、前述のコンテンツでは、指がサブViwからスライドし始めると想定されています。指が外側の親ビューからスライドし始めた場合、親ビューが上にフリングすると、子ビューはフリングを続けることができず、すぐに停止し、継続的なネストされたスライドを実現できません。
これは、アセンブリのネストされたスライドので、消費からのみのシフトであるNestedScrollingChild
のNestedScrollingParent
ではないから、NestedScrollingParent
とNestedScrollingChild
理由だけで、NestedScrollingChild
派遣するためには、NestedScrollingParent
発送することはできません。
あなたから達成したい場合はスライドコヒーレント、手動でしかそのサブビューに配布し、トップの親ビューのスライド変位の残りの後、親ビューのイベント配信を無効にすることができ、何も特に良い方法はありません。(最初に穴を掘って、より良い方法があるかどうかを確認します。ネストされたスライドコンポーネントを拡張することで、目標を達成できます)NestedScrollingParent
NestedScrollingChild
チップ
NestedScrollingParent
そしてNestedScrollingChild
合計3つのバージョン。
最も古いのはNestedScrollingParent
、NestedScrollingChild
スクロールとフリングのインターフェイスのセットが別々に処理されるため、不必要に複雑になるためです。
その後、私は前の世代から来NestedScrollingParent2
てNestedScrollingChild2
継承しましたが、それは距離スクロールの再統合プロセスに飛び込みます。上記のネストされたスライディングコンポーネントは、第2世代を指します。
その後、さらにNestedScrollingParent3
及びNestedScrollingChild
第二世代と比較して増加第二世代から継承されたdispatchNestedScroll
、とonNestedScroll
に親ビュー消費後の変位、即ち変位を摺動部分を消費することができ、消費電力値consumed
通知サブ表示のアレイ。第2世代は、子ビューに親ビューの消費値を通知しません。一般的に、ネストされたスライドを自分で実装する場合は、第2世代以降のインターフェイスを実装するだけで済みます。第一世代は基本的に使用されなくなりました。
注:NestedScrollView
RecyclerViewの子である場合は注意が必要です。コンテンツが無限に長いレイアウトになる可能性がある場合はこれを表示します。サブビューの高さを制限するために使用する必要がありますwrap_content
。設定されたRecyclerViewの高さは使用しないでください。そのためNestedScrollView
測定する際に、子ビューの制限はありませんUNSPECIFIED
あなたは背が高く持つようにしたいどのように高いことは制限、RecyclerView。内部アイテムが多すぎる場合のRecyclerViewと同様にwrap_content
、すべてのアイテムの場合のRecyclerViewが表示され、リカバリなしと同等になります。これにより、多くのメモリが消費されます。setVisibility
可視性を変更するために呼び出すと、非表示から可視になりますが、すべてのアイテムのテストレイアウトプロセスが即座に呼び出され、Catonになります。これは私がプロジェクトで実際に遭遇した問題です。
3つのマルチレベルのネストされたスライディング
私たちはそれを知ってNestedScrollingParent
おりNestedScrollingChild
、彼らの巣のスライドを実現するためにカスタマイズするために使用することができます。ビューが2つのインターフェイスを同時に実装する場合、子のスライドを受け入れるだけでなく、スライドを親に分散してチェーンを形成できることは容易に想像できます。図に示すように、マルチレベルのネストされたスライディングのコア原則はこれに由来します。
原理は実際には複雑ではありません。以下の擬似コードで示しましょう。
-
ために
NestedScrollingParent
@Override public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) { scrollByMe(dx, dy); ... consumed[0] = dxConsumed; consumed[1] = dyConsumed; }
-
仲介者の場合、つまり
NestedScrollingParent
、NestedScrollingChild
ミドルビューを達成しながら@Override public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) { // 先分发,再消费。当然也可以先以先消费,再分发,这取决于业务 dispatchNestedPreScroll(dispatchNestedPreScroll(dx, dy, consumed, null, type); int dx -= consumed[0]; int dy -= consumed[1]; scrollByMe(dx, dy); consumed[0] = dxConsumed; consumed[1] = dyConsumed; }
-
最内層には
NestedScrollingChild
、通常、RecyclerViewを使用できます。
マルチレベルのネストされたスライドでは、ビジネスに応じて上下にスライドするプロセスで各レイヤーの優先度を設定できます。
作業中のプロジェクトはリリースされていないため、掲載されません。インターネット上で見つかったインスタントアプリのマルチレベルのネストされたスライドの画像は次のとおりです。
第4に、ネストされたスライドコンポーネントで使用されるデザインパターン
要約すると、それについて話し合います。
-
戦略モード
NestedScrollingParent
そしてNestedScrollingChild
、インターフェースのペア、スライド効果によって達成される入れ子の異なるペアを達成するためのビューの異なるインターフェース。同時に、インターフェースを使用することでスケーラビリティーも保証されます。 -
エージェンシーモデル
上述したようにスライディングインタフェースビューの実装を入れ子にする方法は、転送台車がエージェントに対して特異的である場合、
NestedScrollingParentHelper
及びNestedScrollingChildHelper
二つのクラスによって提供され、実現にSDKへNestedScrollingParent
とNestedScrollingChild
次のインタフェースが見つかりました:This interface should be implemented by ViewGroup subclasses that wish to support scrolling operations delegated by a nested child view. Classes implementing this interface should create a final instance of a NestedScrollingParentHelper as a field and delegate any View or ViewGroup methods to the NestedScrollingParentHelper methods of the same signature.
-
アダプターモード/外観モード
RecyclerView
NestedScrollingChild2
はインターフェースを実装しますが、その親ビューがNestedScrollingParent
インターフェースの生成を実現する場合、どうすればよいですか?これは、ネストされたスライドコンポーネントの異なるバージョンに互換性がある必要があることを意味します。互換性を実現するViewCompat
には、次のように使用します。// ViewCompat.java public static void onNestedPreScroll(ViewParent parent, View target, int dx, int dy, int[] consumed, int type) { if (parent instanceof NestedScrollingParent2) { // First try the NestedScrollingParent2 API ((NestedScrollingParent2) parent).onNestedPreScroll(target, dx, dy, consumed, type); } else if (type == ViewCompat.TYPE_TOUCH) { // Else if the type is the default (touch), try the NestedScrollingParent API if (Build.VERSION.SDK_INT >= 21) { try { parent.onNestedPreScroll(target, dx, dy, consumed); } catch (AbstractMethodError e) { Log.e(TAG, "ViewParent " + parent + " does not implement interface " + "method onNestedPreScroll", e); } } else if (parent instanceof NestedScrollingParent) { ((NestedScrollingParent) parent).onNestedPreScroll(target, dx, dy, consumed); } } }
スライドはすべての子を分散
ViewCompat
し、親に渡される前に静的メソッドfinalによって、このクラスと静的メソッドを介して、ネストされたスライドアセンブリのさまざまなバージョンとの互換性を実現します。同時に、ViewCompat
使いやすいインターフェースは外部に公開され、互換性のあるプロセスはそれ自体の内部に隠されています。これは一種の外観モードと見なすこともできます。