SlideShare a Scribd company logo
Coordinator Layout Behavior
kyobashi.dex #2
自己紹介
釘宮 愼之介 / @kgmyshin
・ Androidエンジニア
・ Androidエンジニア
今回お話すること
CoordinatorLayoutのBehaviorについて
本当はCoordinatorLayoutについて隅から隅まで話そうと思ったけど
時間がなさそうだったので、今回はBehaviorに焦点を当てます。
この発表で達成したいこと
聴いてくれた方が、聴き終わったあとに
Behaviorの仕組みを理解し、
右のようなカスタムBehaviorを
作れるようになっている状態にすること。
目次
・ CoordinatorLayoutとは
・ Behaviorとは
・ Behaviorの仕組み
・ すでにあるBehaviorたち
・ カスタムBehaviorを作ってみる
CoordinatorLayoutとは
CoordinatorLayoutというのは子ビュー同士が
相互に動くようなインタラクションをする場合に使われるViewGroupです。
とくにMaterial DesignガイドラインのScrolling techniquesを実現するときに使う印象。
Coordinator Layout Behavior
Behaviorとは
CoordinatorLayoutの子ビューの動きのプラグインです。
だいたいがこの二つのメソッドをOverrideして使っているみたい
• layoutDependsOn
• onDependentViewChanged
Behaviorの仕組み(簡易版)
これ以外にも
TouchEventやScrollのイベントが取れたりもする
・onNestedFling
・onNestedPreFling
・onNestedPreScroll
・onNestedScroll
・onTouchEvent
:
実際のBehaviorを見てみましょう
FloatingActionButton.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 説明のために一部ソースを削除してます
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 説明のために一部ソースを削除してます
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 説明のために一部ソースを削除してます
onPreDrawをトリガーにしている
AppBarLayout.ScrollingViewBehavior
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
@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;
}
@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;
}
SwipeDismissBehavior
下記二つは実装していない。
• layoutDependsOn
• onDependentViewChanged
タッチイベントでごりごりやってる。
カスタムBehaviorを作ってみる
すごく簡単なやつ
• layoutDependsOn
• onDependentViewChanged
下記を実装するだけ
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;
}
}
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;
}
}
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;
}
}
注意 コンストラクタも実装しよう
public CustomBehavior(Context context, AttributeSet attrs) {
}
Coordinator Layout Behavior
リフレクションに失敗して落ちます
まとめ
・ Behaviorを使うと他の子ビューに依存した動きを定義しやすくなります。
・ 使う場合は大抵 layoutDependsOn とonDependentViewChanged を
Overrideすればなんとかなります。
宣伝
・ shinobu.apkってのやります!
http://shinobu-apk.connpass.com/event/24921/
shinobu.apkとは
「Shinobu Okanoと愉快な仲間たちが繰り広げるファンタジーな勉強会」
です。
ご静聴ありがとうございました。

More Related Content

PDF
Android Architecture
PDF
これからの設計の話をしよう
PDF
Better parking experience with Automatic - Api Days San Francisco
PDF
このあと滅茶苦茶LGTMした
PDF
ChromeとAndroidの 過去・現在・未来 ver 0.1
PDF
ExtraLayoutSpace of RecyclerView
PDF
例の縛るやつ(Data binding)
PDF
OSSで楽に作るGo言語クライアントツール
Android Architecture
これからの設計の話をしよう
Better parking experience with Automatic - Api Days San Francisco
このあと滅茶苦茶LGTMした
ChromeとAndroidの 過去・現在・未来 ver 0.1
ExtraLayoutSpace of RecyclerView
例の縛るやつ(Data binding)
OSSで楽に作るGo言語クライアントツール

Viewers also liked (20)

PDF
Android development at mercari 2015
PDF
Dependency injection
PDF
Titanium 3.3 / 3.4 と iOS で気をつけたいこと
PDF
FirefoxOSで学ぶJavaScript作法
PDF
ZTE OPEN を日本語化(バージョンアップ)してみる
PDF
Firebase Test Lab 無料枠を使ってみました。
PDF
Wearable realm
PDF
読むと怖くないDagger2
PDF
Architecture driven development のすすめ
PDF
Android で Realm を使ってみよう
PDF
Whats's new in Android Studio at Google I/O extended in Fukuoka
PDF
Androidオールスターズ2016 yanzm
PDF
droidgirls Recyclerview
PDF
Model View Presenter for Android
PDF
Master of RecyclerView
PPTX
Implementing Domain-Driven Design: Part 1
PDF
オブジェクト指向ワークショップ 201507版
PDF
Windows で動かす TensorFlow
PPTX
某S社のddd(メイリオ)
PDF
Android概要資料
Android development at mercari 2015
Dependency injection
Titanium 3.3 / 3.4 と iOS で気をつけたいこと
FirefoxOSで学ぶJavaScript作法
ZTE OPEN を日本語化(バージョンアップ)してみる
Firebase Test Lab 無料枠を使ってみました。
Wearable realm
読むと怖くないDagger2
Architecture driven development のすすめ
Android で Realm を使ってみよう
Whats's new in Android Studio at Google I/O extended in Fukuoka
Androidオールスターズ2016 yanzm
droidgirls Recyclerview
Model View Presenter for Android
Master of RecyclerView
Implementing Domain-Driven Design: Part 1
オブジェクト指向ワークショップ 201507版
Windows で動かす TensorFlow
某S社のddd(メイリオ)
Android概要資料
Ad

More from shinnosuke kugimiya (6)

PDF
Framework code reading
PDF
just one line
PDF
KotlinつかってQiitaクライアント作った時の話
PDF
あの日見たMVCを僕たちはまだ知らない for RoR
PDF
開発効率アンチパターン
PDF
Reactive android
Framework code reading
just one line
KotlinつかってQiitaクライアント作った時の話
あの日見たMVCを僕たちはまだ知らない for RoR
開発効率アンチパターン
Reactive android
Ad

Coordinator Layout Behavior