おもろいことしかやらない

🗣: バイクに乗ったり、ものづくりしたり、ひたすら寝たり。

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.com

RecyclerViewは別途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