2016年11月14日月曜日

ViewAnimationUtils.createCircularReveal() を使って FAB の transforming を実現する - with Transition API -

ViewAnimationUtils.createCircularReveal() を使って FAB の transforming を実現する
では、直接Activityに複雑なアニメーションを記述しました。それにより、本質的なコード(toolsContainer と fab の visibility の切り替え)がアニメーションのコードに埋もれてしまい、何をやっているのかわかりずらい状況になっていました。
そこで Transition API を使ってアニメーション部分を Activity から引き剥がしました。

完全な実装は
https://github.com/yanzm/FabTransformingSample
にあります。

MainActivity からは Animator オブジェクトが完全になくなり、RecyclerViewやバックキー部分のコードを追加しても前回より短くなっています。 visibility の切り替えなど view のパラメータ値の変更だけになり、何をやっているのかがわかりやすくなりました。 アニメーション部分は FabTransformation というクラスにまとめています。 public class MainActivity extends AppCompatActivity { private static final int HORIZONTAL_FACTOR = 2; private float diff; private ViewGroup sceneRoot; private View toolsContainer; private View tools; private FloatingActionButton fab; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolsContainer = findViewById(R.id.tools_container); tools = findViewById(R.id.tools); fab = (FloatingActionButton) findViewById(R.id.fab); sceneRoot = (ViewGroup) findViewById(R.id.scene_root); sceneRoot.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int[] toolsLocation = new int[2]; toolsContainer.getLocationInWindow(toolsLocation); int[] fabLocation = new int[2]; fab.getLocationInWindow(fabLocation); diff = (toolsLocation[1] + toolsContainer.getHeight() / 2) - (fabLocation[1] + fab.getHeight() / 2); final float pivotX = fabLocation[0] + fab.getWidth() / 2 - toolsLocation[0] - diff * HORIZONTAL_FACTOR; toolsContainer.setPivotX(pivotX); tools.setPivotX(pivotX); sceneRoot.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { changeFabMode(true, true); } }); changeFabMode(false, false); // recycler view setup final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); recyclerView.setAdapter(new AndroidVersionAdapter()); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState != RecyclerView.SCROLL_STATE_IDLE) { if (fab.getVisibility() != View.VISIBLE) { changeFabMode(false, true); } } } }); } @Override public void onBackPressed() { if (fab.getVisibility() != View.VISIBLE) { changeFabMode(false, true); return; } super.onBackPressed(); } private void changeFabMode(boolean transformed, boolean animate) { if (animate) { final TransitionSet transition = new FabTransformation(transformed, fab.getHeight() / 2f); TransitionManager.beginDelayedTransition(sceneRoot, transition); } final float baseMargin = getResources().getDimension(R.dimen.fab_margin); final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) fab.getLayoutParams(); params.bottomMargin = (int) (baseMargin - (transformed ? diff : 0)); params.setMarginEnd((int) (baseMargin + (transformed ? diff * HORIZONTAL_FACTOR : 0))); fab.setLayoutParams(params); toolsContainer.setVisibility(transformed ? View.VISIBLE : View.INVISIBLE); tools.setVisibility(transformed ? View.VISIBLE : View.INVISIBLE); tools.setScaleX(transformed ? 1f : 0.8f); fab.setVisibility(transformed ? View.INVISIBLE : View.VISIBLE); } } FabTransformation では複数の Transition を組み合わせて FAB の transforming を実現するアニメーションを構築しています。 ここでは Transition API で用意されている ChangeTransformFadeChangeBounds に加えて、ViewAnimationUtils.createCircularReveal() を利用する CircularRevealTransition を作って利用しています。





0 件のコメント:

コメントを投稿