うまくいかんのんでオレオレ実装したったでぇって話Ω\ζ°)チーン
Design Support Library v22.2.0以降、Android 5.x以降ではToastの代わりにSnackbarという肥満の大敵なアレを使うように推奨されとります(。・_・。)
でもってSnackbarの相方としてCoordinatorLayoutちゅうものを使えと、はいはい使いましょう。
Snackbarが他のViewに重なってしまってもいい場合、これは好きにしてくだせぇ。
でもSnackbarが他のViewに重なって欲しくない場合もあるよね?例えばFloatingActionBar(FAB)の上に重なるんじゃねぇ、ってときとか。幸いなことにFABとSnackbarの組み合わせに関しては先人たちの苦心の結果、重ならないようにSnackbarのアニメーションに合わせてFABの位置を変更できるようにworkaroundが存在します。
ですがFAB以外だとSnackbarの挙動を都合よくコントロールするのは簡単ではないです。
layout_anchorを指定しろだのlayout_anchorGravityを指定しろだのぐちゃぐちゃ抜かすんじゃねぇえ、うまく動きませーん(●`ε´●)
とりあえず自分がしたかったのは、UIは基本的にFragmentで実装・表示していて、でも特定のメッセージはアプリグローバルなのでFragment外で表示したい(Activity毎に表示したい)、メッセージの表示に合わせてSnackbarの様にアニメーションしてながらびビニョォーンと大きくなってその分Fragmentは小さくなって欲しい、Fragmentをremove/replaceしてもSnackbarは表示したままにしたい、でもってユーザーが操作(タッチ♥)してはじめてうにょ~んと消えるようにしたいってことなのです。たったそれだけなのにぃ〜(T_T)
でも標準のSnackbarだと簡単には出来ませんでした。たぶんBehaviorを自前実装すればいけるんじゃないかなぁと思ったもののめんどくさいんじゃぁってことでボツ(●`ε´●)めんどくさいことは嫌い(-_-;)
ということで、車輪の再発見みたいな?
まぁようするにSnackbarみたいにアニメーションしながらメッセージ表示領域の表示・非表示が切り替えれることができればいいんでしょってことで。
普通ならViewアニメーションでいいのですが、何も考えずにサンプルのままに作るとうまく動きません。デフォルトのViewアニメーションでは見た目は変わるのですが、実際のViewの大きさは変わらないのです。
なのでみた目だけじゃなくてViewの実際の大きさが変わるようにViewアニメーションを実装しないといけないのです。
酔ってきたので中略(*ノω・*)テヘ
ということで(どういうことだ?)実際のViewのサイズを変更するAnimationを作りました。じゃぁ〜っん(^o^)/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package com.serenegiant.view.animation; import android.support.annotation.NonNull; import android.view.View; import android.view.animation.Animation; import android.view.animation.Transformation; /** * Viewのりサイズを行うAnimationクラス * 見た目だけじゃなくて実際のサイズも変更する */ public class ResizeAnimation extends Animation { @NonNull private final View mTargetView; private final int mStartWidth, mStartHeight; private final int mDiffWidth, mDiffHeight; public ResizeAnimation(@NonNull final View view, final int startWidth, final int startHeight, final int endWidth, final int endHeight) { mTargetView = view; mStartWidth = startWidth; mStartHeight = startHeight; mDiffWidth = endWidth - startWidth; mDiffHeight = endHeight - startHeight; } @Override protected void applyTransformation(final float interpolatedTime, final Transformation t) { super.applyTransformation(interpolatedTime, t); // this is empty method now final int newWidth = (int)(mStartWidth + mDiffWidth * interpolatedTime); final int newHeight = (int)(mStartHeight + mDiffHeight * interpolatedTime); mTargetView.getLayoutParams().width = newWidth; mTargetView.getLayoutParams().height = newHeight; mTargetView.requestLayout(); } @Override public void initialize(final int width, final int height, final int parentWidth, final int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); } @Override public boolean willChangeBounds() { return (mDiffWidth != 0) || (mDiffHeight != 0); } } |
あとはこやつのインスタンスを適当に生成してView#startAnimationで呼び出すだけ。
1 2 3 4 5 6 7 8 9 10 11 |
final ResizeAnimation expandAnimation = new ResizeAnimation(mMessagePanelView, mRootView.getWidth(), 0, mRootView.getWidth(), getResources().getDimensionPixelSize(R.dimen.bottom_message_panel_height)); expandAnimation.setDuration(DURATION_RESIZE_MS); expandAnimation.setAnimationListener(mAnimationListener); view.setTag(R.id.visibility, 1); view.setTag(R.id.auto_hide_duration, autoHideDurationMs); view.setVisibility(View.VISIBLE); view.startAnimation(expandAnimation); |
細かいことを気にしちゃいけませーん、ハゲるよ?
あとはうまぁーく呼び出すとSnackbarのようにViewを表示できます。(^^ゞ 例えばこんな感じ。CoordinatorLayoutなんていりません、Relativelayoutで十分です。
動画の灰色の帯の部分から上はFramgnetで表示しています。その下のナビゲーションバーの上からビニョォーンと出てくる部分(すなっくバーもどき)は一見Snackbarのように見えますが単なるViewで、先ほどのResizeAnimationを適用しているだけです。
オリジナルのSnackbarと違ってレイアウトxmlやらプログラムやらでゴニョゴニョせんと都合良くは表示できんけど、でも代わりにどんなViewでもSnackbar風に表示できるし、どんなView…たとえそれが先ほどの動画のようにFragmentであっても押しのけて重ならないように表示できるのです(^o^)v
Snackbarの設定を何時間も悩む暇があるんならとっとと自分で作ればいいんだよ。30分もあれば作れるでしょ?
ということで、さよなら〜(^.^)/~~~
コメント
[…] 時代はSnackbarだぜぇーといってみたものの(。・_・。)の第2段(^o^)v […]