Androidのネストされたスライドの概要

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のレイアウトによって提供さ達成することができているAppBarBehaviorscrollFlagデカップリングの使用が行われ、さまざまな効果をカスタマイズすることができますと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として指定されscrollRecyclerViewに指定が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イベント方法でdispatchNestedPreScrollNestedScrollingParent
  • NestedScrollingParentonNestedPreScroll受信したDXとDYと消費。変位に消費int[] consumedconsumedアレイは2のint型の長さの配列であり、consumed[0]x軸消費の代表、consumed[1]y軸消費の代表
  • NestedScrollingChildint[] consumedget後、配列NestedScrollingParentが消費された変位、残りの変位を差し引いた後に取得され、その後、独自の消費によって取得されます

スライド変位の伝達方向は、下図のように子→親→子からです。子がRecyclerviewの場合、最初に変位を親レイアウトに転送して消費し、次に親レイアウトをスライドさせます。親レイアウトがスライドできないところまでスライドすると、この時点でRecyclerviewがすべてのディスプレイスメントを消費します。このとき、Recyclerviewは自動的にスライドを開始し、ネストされたスライドを形成します。効果は前の例のようになります。

変位伝達プロセス

dispatchNestedScrollそして、onNestedScroll行動原理上のpreScroll、しかし、2枚のネストされたスライドとpreScroll逆順を構築するこの方法のように、消費者は、ビューの子は、親ビューの消費によって再び時間を消費し、することはできません、最初の子ビューです。

このメカニズムは、指がビューを離れるACITON_UPときに、イベント、この時点で子Velocityが変位dxまたはdyフローの前に流れて繰り返されるときに生成されるフリングもサポートします。@NestedScrollType int type判定値TYPE_TOUCHTYPE_NON_TOUCHTYPE_TOUCHスライド可能で、TYPE_NON_TOUCH投げつけるています。

Androidのどのビューがこのスライドメカニズムを使用していますか?
  • NestedScrollingParentインターフェイスの実装ビューNestedScrollViewは次のとおりです:CoordinatorLayoutMotionLayoutなど。
  • 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はどのように親ビューに転送し、さonNestedPreSrollonNestedScrollそれ?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からスライドし始めると想定されています。指が外側の親ビューからスライドし始めた場合、親ビューが上にフリングすると、子ビューはフリングを続けることができず、すぐに停止し、継続的なネストされたスライドを実現できません。

これは、アセンブリのネストされたスライドので、消費からのみのシフトであるNestedScrollingChildNestedScrollingParentではないから、NestedScrollingParentNestedScrollingChild理由だけで、NestedScrollingChild派遣するためには、NestedScrollingParent発送することはできません。

あなたから達成したい場合はスライドコヒーレント、手動でしかそのサブビューに配布し、トップの親ビューのスライド変位の残りの後、親ビューのイベント配信を無効にすることができ、何も特に良い方法はありません。(最初に穴を掘って、より良い方法があるかどうかを確認します。ネストされたスライドコンポーネントを拡張することで、目標を達成できます)NestedScrollingParentNestedScrollingChild

チップ

NestedScrollingParentそしてNestedScrollingChild合計3つのバージョン。

最も古いのはNestedScrollingParentNestedScrollingChildスクロールとフリングのインターフェイスのセットが別々に処理されるため、不必要に複雑になるためです。

その後、私は前の世代からNestedScrollingParent2NestedScrollingChild2継承しましたが、それは距離スクロールの再統合プロセスに飛び込みます。上記のネストされたスライディングコンポーネントは、第2世代を指します。

その後、さらにNestedScrollingParent3及びNestedScrollingChild第二世代と比較して増加第二世代から継承されたdispatchNestedScroll、とonNestedScrollに親ビュー消費後の変位、即ち変位を摺動部分を消費することができ、消費電力値consumed通知サブ表示のアレイ。第2世代は、子ビューに親ビューの消費値を通知しません。一般的に、ネストされたスライドを自分で実装する場合は、第2世代以降のインターフェイスを実装するだけで済みます。第一世代は基本的に使用されなくなりました。

NestedScrollViewRecyclerViewの子である場合は注意が必要です。コンテンツが無限に長いレイアウトになる可能性がある場合はこれを表示します。サブビューの高さを制限するために使用する必要がありますwrap_content。設定されたRecyclerViewの高さは使用しないでくださいそのためNestedScrollView測定する際に、子ビューの制限はありませんUNSPECIFIEDあなたは背が高く持つようにしたいどのように高いことは制限、RecyclerView。内部アイテムが多すぎる場合のRecyclerViewと同様にwrap_content、すべてのアイテムの場合のRecyclerViewが表示され、リカバリなしと同等になります。これにより、多くのメモリが消費されます。setVisibility可視性を変更するために呼び出すと、非表示から可視になりますが、すべてのアイテムのテストレイアウトプロセスが即座に呼び出され、Catonになります。これは私がプロジェクトで実際に遭遇した問題です。

3つのマルチレベルのネストされたスライディング

私たちはそれを知ってNestedScrollingParentおりNestedScrollingChild、彼らの巣のスライドを実現するためにカスタマイズするために使用することができます。ビューが2つのインターフェイスを同時に実装する場合、子のスライドを受け入れるだけでなく、スライドを親に分散してチェーンを形成できることは容易に想像できます。図に示すように、マルチレベルのネストされたスライディングのコア原則はこれに由来します。

画像-20210304170155409.png

原理は実際には複雑ではありません。以下の擬似コードで示しましょう。

  • ために 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;
        }
    
    
  • 仲介者の場合、つまりNestedScrollingParentNestedScrollingChildミドルビューを達成しながら

     @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へNestedScrollingParentNestedScrollingChild次のインタフェースが見つかりました:

    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.
    
    
  • アダプターモード/外観モード

    RecyclerViewNestedScrollingChild2はインターフェースを実装しますが、その親ビューが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使いやすいインターフェースは外部に公開され、互換性のあるプロセスはそれ自体の内部に隠されています。これは一種の外観モードと見なすこともできます。

おすすめ

転載: blog.csdn.net/zhireshini233/article/details/115034973