指に追従するアニメーション
「Lollipop のステータスバーを引っ張り出した時に、ステータスバーのアイコンが動いたり、設定アイコンがくるくるってなるけど、どうやってるの?」
心の声「知らんがな(´・ω・`)ggry」
ggっても出てこなかった。
確かに、どうやっているんだろう。
調査
エミュレータを起動して、Hierarchy View を見てみると、ステータスバーの当該の部品は StatusBarHeaderView というビューらしい。そこからソースを追ってみた。
ざっくり仕組みを説明すると、
- QuickSettingsパネルの高さに連動して、変化量を計算して設定
- onLayoutを契機として、変化量からそれぞれの部品のアニメーションさせる値を計算
- それぞれの部品にsetX()やsetTranslationX()やsetRotation()等を設定して部品を再描画
変化量を計算して設定
呼び出し元では、QuickSettingsパネルの高さから、変化量(t: transform値)を計算している。
1107 private void setQsExpansion(float height) { ... 1120 mHeader.setExpansion(getHeaderExpansionFraction());
1158 private float getHeaderExpansionFraction() { 1159 if (!mKeyguardShowing) { 1160 return getQsExpansionFraction();
635 private float getQsExpansionFraction() { 636 return Math.min(1f, (mQsExpansionHeight - mQsMinExpansionHeight) 637 / (getTempQsMaxExpansion() - mQsMinExpansionHeight));
変化量は、0.0, 0.1, 0.2, 0.3, .., 1.0 のようになる。
計算方法
変化量=((現在の位置)-(移動前の位置))/((移動後の位置)-(移動前の位置))
ただし、変化量<=1.0
計算して求めた変化量をStatusBarHeaderViewに設定する。
454 public void setExpansion(float t) { 455 if (!mExpanded) { 456 t = 0f; 457 } 458 mCurrentT = t;
onLayout契機に変化量からアニメーションさせる値を計算
位置が変化するたびにonLayoutが通知される。
onLayoutを契機として、それぞれの部品をアニメーションさせる値を計算する。
183 @Override 184 protected void onLayout(boolean changed, int l, int t, int r, int b) { 185 super.onLayout(changed, l, t, r, b); 186 if (mCaptureValues) { 187 if (mExpanded) { 188 captureLayoutValues(mExpandedValues); 189 } else { 190 captureLayoutValues(mCollapsedValues); 191 } 192 mCaptureValues = false; 193 updateLayoutValues(mCurrentT);
updateLayoutParamsの引数 t: Transform値は、0.0, 0.1, 0.2, 0.3, .., 1.0 のように変化していく。
470 private void updateLayoutValues(float t) { 471 if (mCaptureValues) { 472 return; 473 } 474 mCurrentValues.interpoloate(mCollapsedValues, mExpandedValues, t); 475 applyLayoutValues(mCurrentValues);
スケールや位置や回転を設定する。
591 private void applyLayoutValues(LayoutValues values) { //時計のサイズ(スケール)を変更 592 mTime.setScaleX(values.timeScale); 593 mTime.setScaleY(values.timeScale); //時計の位置を変更 594 mClock.setY(values.clockY - mClock.getHeight()); ... //設定アイコンの位置を変更しつつ回転 622 mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); 623 mSettingsButton.setTranslationX(values.settingsTranslation); 624 mSettingsButton.setRotation(values.settingsRotation);
参考
「onMeasureとonLayoutについて理解する」
onLayoutについてわかりやすく解説されています。
件のステータスバーのアニメーションでは、onLayoutを契機としています。
関連記事
ViewPager のアニメーションについてまとめた記事。
Transform値の考え方は、ここと共通します。