Plaidとは
Google製のマテリアルデザインの参考実装のアプリです。結構アニメーションなどで参考になる点が多いです。
ちょっとどういう風にアニメーションって実装するのが普通なのかよくわからないので、読んでみたいなと思いました。
アプリ自体は「Plaid - デザイナーなら使いたいAndroidアプリ」として紹介されたりなど普通に使えるものとなっています。
http://www.moongift.jp/2015/11/plaid-%E3%83%87%E3%82%B6%E3%82%A4%E3%83%8A%E3%83%BC%E3%81%AA%E3%82%89%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84android%E3%82%A2%E3%83%97%E3%83%AA/
普通に画面遷移とかのソースコードを読もうと思っていたのですが、その前に起動でもいろいろいやっていたので見てみました。
起動部分
起動するだけですが3つの表示が見て取れます。
- タイトルのアニメーション
- 最初の3種類の黒色画像表示
- 画像の色の彩度のアニメーション
タイトルのアニメーション
最初からハックっぽいやつで申し訳ないです。。
コメントにあるように良くない実装ではあるのですが、ToolbarのTitleをgetChildAt(0)でタイトルのTextViewを取り出してアニメーションさせています。
アニメーションにはView Property Animationを利用しています。(結構これを使うと簡潔にかけて良いですね)
http://android-developers.blogspot.jp/2011/05/introducing-viewpropertyanimator.html
letterSpacingをアニメーションさせたかったようですがうまくアニメーション出来なかった用で大きさのアニメーションになっているようです。
getFastOutSlowInInterpolatorで取得しているのはAndroid 5.0以上で利用できるInterpolatorですが、Support LibraryにFastOutSlowInInterpolatorがあるのでそれで利用できます。
Activity#onCreateから呼び出して利用します。
private void animateToolbar() {
// this is gross but toolbar doesn't expose it's children to animate them :(
View t = toolbar.getChildAt(0);
if (t != null && t instanceof TextView) {
TextView title = (TextView) t;
// fade in and space out the title. Animating the letterSpacing performs horribly so
// fake it by setting the desired letterSpacing then animating the scaleX ¯\_(ツ)_/¯
title.setAlpha(0f);
title.setScaleX(0.8f);
title.animate()
.alpha(1f)
.scaleX(1f)
.setStartDelay(300)
.setDuration(900)
.setInterpolator(AnimUtils.getFastOutSlowInInterpolator(this));
}
....
最初の3種類の黒色画像
プログレスバーが終わったあとのアニメーションですが。
最初の黒い画像が何種類か出てきます。
フェードインのように見せるために必要?のようです。
// need both placeholder & background to prevent seeing through shot as it fades in
holder.image.setBackground(
shotLoadingPlaceholders[position % shotLoadingPlaceholders.length]);
色の指定は以下のようになっているようです
https://github.com/nickbutcher/plaid/blob/bd64f9c3fce82ec2da1ee001f9aedf1f74a26533/app/src/main/res/values/colors.xml#L84-L84
色の彩度のアニメーション
画像の色にご着目ください。
こちらマテリアルデザインのLoading imagesにあるものになります。
https://material.google.com/patterns/loading-images.html
彩度(saturation)を変えてアニメーションさせています。
これはColorFilterを使って実現できるようです。
holder.image.setHasTransientState(true);
final ObservableColorMatrix cm = new ObservableColorMatrix();
final ObjectAnimator saturation = ObjectAnimator.ofFloat(
cm, ObservableColorMatrix.SATURATION, 0f, 1f);
saturation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener
() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// just animating the color matrix does not invalidate the
// drawable so need this update listener. Also have to create a
// new CMCF as the matrix is immutable :(
holder.image.setColorFilter(new ColorMatrixColorFilter(cm));
}
});
saturation.setDuration(2000L);
saturation.setInterpolator(getFastOutSlowInInterpolator(host));
saturation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
holder.image.clearColorFilter();
holder.image.setHasTransientState(false);
}
});
saturation.start();
下位互換性について
APIレベル的にはView#setHasTransientState()がAPI Level 16(Android 4.1)でしたが、ViewCompatにもあり、呼ばなくてもこちらは特に問題にならないので普通にAPI Level 15(Android 4.0.3)以上などにしていれば問題なく動きそうです(ちゃんとは検証できていません。)
かんたんに確認するには
Plaidは結構でかいアプリなので、アニメーションの部分だけのコードを抜き出して作ってみました。(今は起動部分のみ)
また一応Support Libraryに置き換えを行っているのでAndroid 4.0でも動くはずです。
https://github.com/takahirom/PlaidAnimation
シリーズ追加しました
マテリアルデザインのアニメーション実装(Google製 Plaid) Part 2: Ripple + Elevation
http://qiita.com/takahirom/items/2e67333adecb189dbc93