32
Coordinator Layout Behavior kyobashi.dex #2

Coordinator Layout Behavior

Embed Size (px)

Citation preview

Page 1: Coordinator Layout Behavior

Coordinator Layout Behavior

kyobashi.dex #2

Page 2: Coordinator Layout Behavior

自己紹介

釘宮 愼之介 / @kgmyshin

・ Androidエンジニア

・ Androidエンジニア

Page 3: Coordinator Layout Behavior

今回お話すること

CoordinatorLayoutのBehaviorについて

本当はCoordinatorLayoutについて隅から隅まで話そうと思ったけど 時間がなさそうだったので、今回はBehaviorに焦点を当てます。

Page 4: Coordinator Layout Behavior

この発表で達成したいこと

聴いてくれた方が、聴き終わったあとに

Behaviorの仕組みを理解し、

右のようなカスタムBehaviorを

作れるようになっている状態にすること。

Page 5: Coordinator Layout Behavior

目次・ CoordinatorLayoutとは

・ Behaviorとは

・ Behaviorの仕組み

・ すでにあるBehaviorたち

・ カスタムBehaviorを作ってみる

Page 6: Coordinator Layout Behavior

CoordinatorLayoutとは

CoordinatorLayoutというのは子ビュー同士が 相互に動くようなインタラクションをする場合に使われるViewGroupです。

とくにMaterial DesignガイドラインのScrolling techniquesを実現するときに使う印象。

Page 7: Coordinator Layout Behavior
Page 8: Coordinator Layout Behavior

Behaviorとは

CoordinatorLayoutの子ビューの動きのプラグインです。

Page 9: Coordinator Layout Behavior

だいたいがこの二つのメソッドをOverrideして使っているみたい

• layoutDependsOn

• onDependentViewChanged

Page 10: Coordinator Layout Behavior

Behaviorの仕組み(簡易版)

Page 11: Coordinator Layout Behavior

これ以外にも TouchEventやScrollのイベントが取れたりもする

・onNestedFling ・onNestedPreFling ・onNestedPreScroll ・onNestedScroll ・onTouchEvent :

Page 12: Coordinator Layout Behavior

実際のBehaviorを見てみましょう

Page 13: Coordinator Layout Behavior

FloatingActionButton.Behavior

Page 14: Coordinator Layout Behavior

FloatingActionButton.Behaviorの各メソッドはこのようになってます。(※1 )

public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { return dependency instanceof Snackbar.SnackbarLayout; }

@Override public boolean onDependentViewChanged( CoordinatorLayout parent, FloatingActionButton child, View dependency ) { if (dependency instanceof Snackbar.SnackbarLayout) { updateFabTranslationForSnackbar(parent, child, dependency); } return false; }

※1 説明のために一部ソースを削除してます

Page 15: Coordinator Layout Behavior

FloatingActionButton.Behaviorの各メソッドはこのようになってます。(※1 )

public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { return dependency instanceof Snackbar.SnackbarLayout; }

@Override public boolean onDependentViewChanged( CoordinatorLayout parent, FloatingActionButton child, View dependency ) { if (dependency instanceof Snackbar.SnackbarLayout) { updateFabTranslationForSnackbar(parent, child, dependency); } return false; }

※1 説明のために一部ソースを削除してます

Page 16: Coordinator Layout Behavior

FloatingActionButton.Behaviorの各メソッドはこのようになってます。(※1 )

public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { return dependency instanceof Snackbar.SnackbarLayout; }

@Override public boolean onDependentViewChanged( CoordinatorLayout parent, FloatingActionButton child, View dependency ) { if (dependency instanceof Snackbar.SnackbarLayout) { updateFabTranslationForSnackbar(parent, child, dependency); } return false; }

※1 説明のために一部ソースを削除してます

Page 17: Coordinator Layout Behavior

onPreDrawをトリガーにしている

Page 18: Coordinator Layout Behavior

AppBarLayout.ScrollingViewBehavior

@Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof AppBarLayout; }

Page 19: Coordinator Layout Behavior

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { final CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior(); if (behavior instanceof Behavior) { // Offset the child so that it is below the app-bar (with any overlap)

final int appBarOffset = ((Behavior) behavior) .getTopBottomOffsetForScrollingSibling(); final int expandedMax = dependency.getHeight() - mOverlayTop; final int collapsedMin = parent.getHeight() - child.getHeight();

if (mOverlayTop != 0 && dependency instanceof AppBarLayout) { // If we have an overlap top, and the dependency is an AppBarLayout, we control // the offset ourselves based on the appbar's scroll progress. This is so that // the scroll happens sequentially rather than linearly final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange(); setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin, Math.abs(appBarOffset) / (float) scrollRange)); } else { setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset); } } return false; }

Page 20: Coordinator Layout Behavior

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { final CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior(); if (behavior instanceof Behavior) { // Offset the child so that it is below the app-bar (with any overlap)

final int appBarOffset = ((Behavior) behavior) .getTopBottomOffsetForScrollingSibling(); final int expandedMax = dependency.getHeight() - mOverlayTop; final int collapsedMin = parent.getHeight() - child.getHeight();

if (mOverlayTop != 0 && dependency instanceof AppBarLayout) { // If we have an overlap top, and the dependency is an AppBarLayout, we control // the offset ourselves based on the appbar's scroll progress. This is so that // the scroll happens sequentially rather than linearly final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange(); setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin, Math.abs(appBarOffset) / (float) scrollRange)); } else { setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset); } } return false; }

Page 21: Coordinator Layout Behavior

SwipeDismissBehavior

下記二つは実装していない。 • layoutDependsOn • onDependentViewChanged

タッチイベントでごりごりやってる。

Page 22: Coordinator Layout Behavior

カスタムBehaviorを作ってみる

すごく簡単なやつ

Page 23: Coordinator Layout Behavior

• layoutDependsOn

• onDependentViewChanged

下記を実装するだけ

Page 24: Coordinator Layout Behavior

public class CustomBehavior extends CoordinatorLayout.Behavior<View> {

public CustomBehavior(Context context, AttributeSet attrs) { }

@Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof AppBarLayout; }

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (dependency instanceof AppBarLayout) { AppBarLayout appBarLayout = (AppBarLayout) dependency; int totalScrollRange = appBarLayout.getTotalScrollRange(); int scrollY = appBarLayout.getTop(); float ratio = -scrollY / (float) totalScrollRange; child.setAlpha(1.f - ratio); } return true; }

}

Page 25: Coordinator Layout Behavior

public class CustomBehavior extends CoordinatorLayout.Behavior<View> {

public CustomBehavior(Context context, AttributeSet attrs) { }

@Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof AppBarLayout; }

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (dependency instanceof AppBarLayout) { AppBarLayout appBarLayout = (AppBarLayout) dependency; int totalScrollRange = appBarLayout.getTotalScrollRange(); int scrollY = appBarLayout.getTop(); float ratio = -scrollY / (float) totalScrollRange; child.setAlpha(1.f - ratio); } return true; }

}

Page 26: Coordinator Layout Behavior

public class CustomBehavior extends CoordinatorLayout.Behavior<View> {

public CustomBehavior(Context context, AttributeSet attrs) { }

@Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof AppBarLayout; }

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (dependency instanceof AppBarLayout) { AppBarLayout appBarLayout = (AppBarLayout) dependency; int totalScrollRange = appBarLayout.getTotalScrollRange(); int scrollY = appBarLayout.getTop(); float ratio = -scrollY / (float) totalScrollRange; child.setAlpha(1.f - ratio); } return true; }

}

Page 27: Coordinator Layout Behavior

注意 コンストラクタも実装しよう

public CustomBehavior(Context context, AttributeSet attrs) { }

Page 28: Coordinator Layout Behavior
Page 29: Coordinator Layout Behavior

リフレクションに失敗して落ちます

Page 30: Coordinator Layout Behavior

まとめ

・ Behaviorを使うと他の子ビューに依存した動きを定義しやすくなります。

・ 使う場合は大抵 layoutDependsOn とonDependentViewChanged を

Overrideすればなんとかなります。

Page 31: Coordinator Layout Behavior

宣伝・ shinobu.apkってのやります!

http://shinobu-apk.connpass.com/event/24921/

shinobu.apkとは

「Shinobu Okanoと愉快な仲間たちが繰り広げるファンタジーな勉強会」

です。

Page 32: Coordinator Layout Behavior

ご静聴ありがとうございました。