MotionLayoutでリッチなUXをxmlのみで表現してみました
長いこと更新をサボってました。。 最近はもっぱらKotlinでのAndroid開発に従事していますが、ビューの原則はMaterialDesignを取り入れ、バラツキのあるデバイスの端末性能を吸収する優秀なプラグインが用意してあったりと、奥深く、ネイティブは楽しい分野だと感じています!
(デザイナーさんから思いもよらぬ仕様を叩きつけられることもありますが…)
勉強がてらに新しい部品に触る事も楽しいです!
そんな感じでいただいたデザインと納期の間で不安に苛まれていたとある日、何某Kotlinイベントに参加してみました。 Droid会議直後の温まった会場でMotionLayoutについて教えていただく機会があり、実装してみたので軽くレビューしていきます🐕
1. xmlファイルでリッチな動きが実現するMotionLayout
実装例・導入方法など詳しくはこちらをご覧ください💁♀️
https://github.com/googlesamples/android-ConstraintLayoutExamples
Google I/O 2018で紹介されているようですね♩ youtu.be
< 実装例gif >(でかくて申し訳ない…)
gfycat.comRecyclerViewは別途Adapterクラスなどの実装が必要なので、実装にはこちらを参照してください。
2. 導入 : build.gradle
build.gradle
dependencies { implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha3' }
3. ベースのxmlを記述する
base.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constraintLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".HogeActivity"> <android.support.constraint.motion.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/design_default_color_primary" app:layoutDescription="@xml/motion" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> <android.support.v7.widget.RecyclerView android:id="@+id/top_recycler_view" android:layout_width="wrap_content" android:layout_height="500dp" android:paddingTop="30dp" android:background="@drawable/recycler_view_bkground" android:scrollbars="vertical"> </android.support.v7.widget.RecyclerView> </android.support.constraint.motion.MotionLayout> </android.support.constraint.ConstraintLayout>
4. motionタグの追加
motion.xml
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <Transition motion:constraintSetStart="@id/base_state" motion:constraintSetEnd="@id/open_state" motion:duration="3000"> <OnSwipe motion:dragDirection="dragUp" motion:touchAnchorId="@id/top_recycler_view" motion:touchAnchorSide="top"> </OnSwipe> </Transition> <ConstraintSet android:id="@+id/base_state"> <Constraint android:id="@id/top_recycler_view"> <Layout motion:layout_width="400dp" motion:layout_height="100dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintVertical_bias="1.0"> </Layout> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/open_state"> <Constraint android:id="@id/top_recycler_view"> <Layout motion:layout_width="400dp" motion:layout_height="500dp" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintBottom_toBottomOf="parent"> </Layout> </Constraint> </ConstraintSet> </MotionScene>
非常にさっくりと説明すると、app:layoutDescription="@xml/motion_activity_first_visit"のように設定したmotion.xmlで該当の部品のアニメーションを指定します。 今回のアニメーションはベースの状態(@id/base_state)とアニメーション終了時の状態(@id/open_state)です。 motionタグで囲う範囲については、アニメーションの可動域となるので、くれぐれも他の要素が消え去らないように注意してください。(プレビューすれば一目瞭然ですが…)
今回はmotion.xmlで、部品上部において上にスワイプする操作で、ビューがプルアップ+ダウンする挙動を制御しています。 フリック(軽く指で弾くような動作、スライドショーをめくるような動き)では反応しないので、適宜使用するタグを付け替えてみてください。
公式のリポジトリの例が豊富なので非常におすすめです。
https://github.com/googlesamples/android-ConstraintLayoutExamples