CoordinatorLayoutの動作ですべてをインターセプトする

記事「Ian Lake Intercepting everything with Coordinator Layout Behaviors」の翻訳に注目してください。



CoordinatorLayout処理することなく、 Android Design Support Libraryを学習することはできません。 デザインライブラリのビューの多くにはCoordinatorLayoutが必要です。 しかし、なぜですか? CoordinatorLayout自体はあまり機能しません。Androidフレームワークの一部であるViewで使用すると、通常のFrameLayoutのように機能します。 それで、彼の魔法はどこから来たのでしょうか? これがCoordinatorLayout.Behaviorがシーンに入る場所です。 BehaviorをCoordinatorLayoutの子ビューに接続することにより、タッチ、ウィンドウのインセット、サイズ変更とレイアウト(測定とレイアウト)、およびネストされたスクロールをキャプチャできます。 デザインライブラリは、ビヘイビアを広範囲に使用して、表示されるほとんどの機能に強度を追加します。







行動の創造



Behaviorの作成は非常に簡単です:クラスをBehaviorから継承します。



ビヘイビア作成の例
public class FancyBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { /** *     FancyBehavior  . */ public FancyBehavior() { } /** *     FancyBehavior  . * * @param context The {@link Context}. * @param attrs The {@link AttributeSet}. */ public FancyBehavior(Context context, AttributeSet attrs) { super(context, attrs); //     //     behavior_ //      Behavior } }
      
      







このクラスで指定されたジェネリック型に注意してください。 この場合、FancyBehaviorを任意のビューに接続できることを示します。 ただし、ビヘイビアを特定のビュータイプに接続できるようにする場合は、次のように記述できます。



 public class FancyFrameLayoutBehavior extends CoordinatorLayout.Behavior<FancyFrameLayout>
      
      





これにより、メソッド内の多数のパラメーターを必要なViewサブタイプにキャストする必要がなくなります-簡単かつ便利に。



一時的なBehavior.setTag() / Behavior.getTag()データの両方を保存し、 onSaveInstanceState() / onRestoreInstanceState()を使用してBehaviorインスタンスの状態を保存するメソッドがあります。 できるだけ簡単にビヘイビアを作成することをお勧めしますが、これらのメソッドを使用すると、状態を保存できるビヘイビアを作成できます。



行動のつながり



もちろん、Behaviorはそれ自体では何もしません。そのため、使用するには、CoordinatorLayoutの子Viewに接続する必要があります。 これを行うには、主に3つの方法があります。プログラムで、XMLで、または注釈を使用して自動的に。



ソフトウェア接続動作


BehaviorをCoordinatorLayout内の各ビューに追加的に接続されたものと考える場合、( レイアウトに関する記事を読んだ場合) ビヘイビアーが各ビューのLayoutParamsに実際に格納されていることに驚かないでください- ビヘイビアーを宣言する必要があるビューの内部にはCoordinatorLayoutがあります。これは、これらのビューだけが、動作を格納できるLayoutParamsの特定のサブタイプを持つためです。



 FancyBehavior fancyBehavior = new FancyBehavior(); CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) yourView.getLayoutParams(); params.setBehavior(fancyBehavior);
      
      





ご覧のとおり、この場合、通常の空のコンストラクターを使用します。 ただし、これは、必要な数のパラメーターを受け取るコンストラクターを作成できないという意味ではありません。 コードを通して何かをするとき、可能性に制限はありません。



XMLを介した接続動作


もちろん、常にコードを使用してすべてを行うと、混乱を招く可能性があります。 ほとんどのカスタムLayoutParamsと同様に、同じことを行う対応するlayout_属性があります。 私たちの場合、これはlayout_behavior属性です:



 <FrameLayout android:layout_height=”wrap_content” android:layout_width=”match_parent” app:layout_behavior=”.FancyBehavior” />
      
      





ここでは、プログラムメソッドとは異なり、 FancyBehaviorコンストラクター(コンテキストコンテキスト、AttributeSet attrs)が常に呼び出されます。 ただし、ボーナスとして、他のカスタム属性を宣言してXML AttributeSetから取得することができます。これは、他の開発者がXMLを介してBehaviorの機能をカスタマイズできるようにする場合に重要です。



:親クラスが分析および理解できるlayout_属性の命名規則と同様に、Behavior内で使用される属性にはbehavior_プレフィックスを使用します



自動動作接続


独自のビヘイビアを必要とする独自のビューを作成する場合(デザインライブラリのほとんどのコンポーネントの場合)、ほとんどの場合、コードまたはXMLを介した一定の手動接続なしで、デフォルトでビヘイビアを有効にする必要があります。 これを行うには、ビューのクラスの上に簡単な注釈を追加するだけです。



 @CoordinatorLayout.DefaultBehavior(FancyFrameLayoutBehavior.class) public class FancyFrameLayout extends FrameLayout { }
      
      





標準の空のコンストラクターを使用してBehaviorが呼び出され、このメソッドがBehaviorのプログラム接続に似ていることがわかります。 layout_behavior属性 DefaultBehavior オーバーライドすることに注意してください。



タッチ傍受



Behaviorをプラグインすると、アクションの準備が整います。 Behaviorの機能の1つは、タッチをインターセプトすることです。



CoordinatorLayoutがない場合、これは通常、 タッチイベントの管理のトレーニングで述べたように、各ViewGroupのサブクラス化を伴いました 。 ただし、 CoordinatorLayoutの場合、 onInterceptTouchEvent()メソッドの呼び出しをBehaviorのonInterceptTouchEvent()メソッドに渡し 、Behaviourがtouch をインターセプトできるようにします 。 このメソッドでtrueを返す場合、 ビヘイビアーonTouchEvent()メソッドを使用して後続のすべてのタッチを受け取ります。これはすべて、Viewから秘密に行われます。 たとえば、これはSwipeDismissBehaviorがどのビューでも機能する方法です



タッチをインターセプトする別のより複雑なケースがあります-相互作用をブロックします。 blocksInteractionBelow()メソッドでtrueを返すだけで十分です。 おそらく、ユーザーがアプリケーションが壊れていると思わないように、何らかの方法で相互作用がブロックされていることを視覚的に表示する必要があります。これが、標準のblockInteractionBelow()機能がgetScrimOpacity()の値に依存する理由です ゼロ以外の値を返すと、ビューの上にすぐに色( getScrimColor() 、デフォルトでは黒)を描画し、タッチ操作をオフにします。 便利に。



ウィンドウ挿入の傍受



ブログを読んだとしましょう。なぜSystemsWindowsに適合したいのですか? 。 そこで、 fitsSystemWindowsの機能について詳しく説明しましたが、システムウィンドウ(ステータスバーやナビゲーションバーなど)の下に描画しないようにするために必要なウィンドウインセットを表示することになりました。 行動はここで証明できます。 ビューがfitsSystemWindows =“ true”の場合、接続された動作はすべて、ビュー自体よりも優先してonApplyWindowInsets()メソッドの呼び出しを受け取ります。



:ほとんどの場合、 ビヘイビアーがウィンドウの挿入全体を処理しない場合、 ViewCompat.dispatchApplyWindowInsets()を使用してこれらの挿入を渡し 、すべての子ビューがWindowInsetsを表示できるようにします。



傍受の測定とレイアウト



これらは、 AndroidがViewを描画する方法の2つの重要なコンポーネントです。 したがって、すべてのイベントのインターセプターとしてのBehaviorは、 onMeasureChild()およびonLayoutChild()メソッドを呼び出して、サイズ変更とレイアウトに関する通知を最初に受け取ることも理にかなっています。



たとえば、汎用のViewGroupを使用してmaxWidthを追加してみましょう。 MaxWidthBehavior.javaクラスに示されているとおり



任意のビューで機能する一般的な動作を作成することは非常に便利です。 ただし、Behaviorをアプリケーション内でのみ使用するかどうかを検討することで、人生を簡素化できることに注意してください(すべてのBehaviorが汎用である必要はありません!)。



ビュー間の依存関係を理解する



上記のすべてには、1つのビューが必要です。 ただし、ビヘイビアーの真の力は、ビュー間の依存関係を構築することで明らかになります。つまり、1つのビューが変更されると、ビヘイビアーはそれに関する通知を受け取り、外部条件に応じて機能を変更します。



ビヘイビアーは、2つの異なる方法でビューを相互に依存させることができます。ビューが別のビューに固定されている場合(暗黙の依存関係)、またはlayoutDependsOn()メソッドで明示的にtrueを返す場合



CoordinatorLayout内のビューがlayout_anchor属性を使用すると、リンクが発生します。 この属性をlayout_anchorGravityと組み合わせると、2つのビューの位置を効率的にリンクできます。 たとえば、 FloatingActionButtonAppBarLayoutに関連付けると、 FloatingActionButton.Behaviorは暗黙的な依存関係を使用して、 AppBarLayoutが画面外にスクロールされた場合にFABを非表示にします。



いずれの場合でも、依存ビューがサイズ変更(サイズまたは位置が変更)されるたびに、依存ビューが削除され、 onDependentViewChanged()されると、 ビヘイビアーonDependentViewRemoved()メソッドの呼び出しを受け取ります。



クールなデザインライブラリ機能のほとんどは、Viewをバンドルする機能のおかげで機能します。 FloatingActionButtonSnackbarの相互作用を例にとってみましょう。 FABの動作は、 CoordinatorLayoutに追加されたSnackbarインスタンスに依存します。次に、 onDependentViewChanged()メソッド呼び出しを使用して、FABを高く移動し、 Snackbarが重ならないようにします



:依存関係を追加すると、マークアップ内のシーケンスに関係なく、ビューは常に依存ビューの後に配置されます。



ネストされたスクロール



ああ、ネストされたスクロール。 このトピックについては、投稿でのみ触れます。 留意すべき点がいくつかあります。



  1. スクロールをネストしたビューで依存関係を宣言しないでください。 CoordinatorLayout内の各ビューは、ネストされたスクロールイベントを受け取ることができます。
  2. ネストされたスクロールは、 CoordinatorLayout内のビューだけでなく、 任意の子ビュー(たとえば、 CoordinatorLayoutの 「子」の「子」の「子」) でも発生する可能性があります。
  3. ネストされたスクロールと呼びますが、実際には単にスクロールと高速スクロール(フリング)を意味します。


ネストされたスクロールイベントは、 onStartNestedScroll()メソッドで開始します。 スクロール軸(水平または垂直-特定の方向へのスクロールは簡単に無視できます) を取得し、さらにスクロールイベントを受け取るにはtrueを返す必要があります



onStartNestedScroll()メソッドでtrueを返した後、ネストされたスクロールは2段階で機能します。





高速スクロールには同様の方法があります(ただし、プリフリング処理方法は、すべてのスクロールを処理するか、まったく処理しないかのいずれかです)。



ネストされた(または高速の)スクロールが終了すると、 onStopNestedScroll()メソッドの呼び出しを受け取ります。 これは、スクロールの終了と、新しいスクロールが開始される前のonStartNestedScroll()メソッドの新しい呼び出しの予想を示します。



たとえば、下にスクロールするときにFloatingActionButtonを非表示にし、上にスクロールするときにFABを表示する場合を考えます。 これを行うには、 ScrollAwareFABBehaviorに見られるように、 onStartNestedScroll()およびonNestedScroll()メソッドをオーバーライドします。



そしてこれはほんの始まりです



Behaviorのすべての部分が興味深いだけである場合、それらがすべて一緒になったときに、魔法が始まります。 詳細については、デザインライブラリのソースコードを参照することを強くお勧めします。 Android SDK SearchのChrome拡張機能は、AOSPコード(Android Open Source Project)を研究するための私のお気に入りのリソースの1つです。 さらに、パス<android-sdk> / extras / android / m2repositoryに沿ってソースコードの最新バージョンを見つけることができます。



Behaviorハッシュタグ#BuildBetterAppsでできることに関する基本的な使い方を教えてください。



Google+のディスカッションに参加して、さらに詳しい情報を入手するにはAndroid Development Patterns Collectionに登録してください!



All Articles