[Android] レイアウトを折りたたみ可能にするライブラリ「ExpandableLayout」を使ってみた

レイアウトを折りたたみ可能にするライブラリ「ExpandableLayout」を使ってみました。
2021.01.29

結論から言うと、簡単にレイアウトの折りたたみ(アニメーション付き)が実装できます。

はじめに

例えば、リスト表示でタイトルのみ表示して詳細情報は表示したくない場合、折りたたみリストがデザイン候補になります。折りたたみリストを使うと画面遷移がないので、ユーザーにとって負担が少ないレイアウトになります。

開発環境

  • OS: MacOS Catalina
  • Android Studio: 4.1.2
  • Language: Kotlin 1.4.21

手順

最初にExpandableLayoutライブラリをプロジェクトに追加します。次にレイアウトファイルを編集します。最後にレイアウトをタッチした時の処理をMainActivityに実装します。

  1. build.gradleにライブラリを追加
  2. レイアウトファイルの編集
  3. MainActivity.ktの編集

アプリレベルのbuild.gradleにライブラリを追加

執筆時点(2021年1月末)の最新バージョンは2.9.2となっています。カードタイプのレイアウトにしたいので、CardViewのライブラリも追加します。

app/build.gradle

dependencies {
    // 省略
    implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2'
    implementation "androidx.cardview:cardview:1.0.0"
}

レイアウトの編集

activity_main.xmlにExpandableLayoutを追加します。ExpandableLayoutではいくつか属性が設定可能です。パララックス(視差効果)も指定できるので、今回とは別用途にも使えそうです。

属性 詳細
app:el_duration 指定された時間で伸縮します。単位はミリ秒 300 500
app:el_expanded 開いた状態で表示するかどうか 真偽値 true false
app:el_parallax 視差の指定 0~1の数値 0, 0.5, 1

src/main/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:id="@+id/titleLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="16dp"
                    android:text="Hello World!"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

            </LinearLayout>

            <net.cachapa.expandablelayout.ExpandableLayout
                android:id="@+id/expandableLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:el_duration="1000"
                app:el_parallax="0.5"
                app:el_expanded="false"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/titleLayout">

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_margin="8dp">

                    <ImageView
                        android:id="@+id/imageView"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@mipmap/ic_launcher"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="8dp"
                        android:text="こんにちは!"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintStart_toEndOf="@+id/imageView"
                        app:layout_constraintTop_toTopOf="parent" />

                </androidx.constraintlayout.widget.ConstraintLayout>

            </net.cachapa.expandablelayout.ExpandableLayout>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivityにタップ時のプログラムを追記

MainActivity.ktを編集してタップ時の動作を実装します。ExpandableLayoutの主なメソッドはexpand、collapse、toggleです。引数でアニメーションのON/OFFが可能です。

メソッド 説明
expand(boolean animate) レイアウトを開きます。引数でアニメーションのON/OFF設定
collapse(boolean animate) レイアウトを閉じます。引数でアニメーションのON/OFF設定
toggle レイアウトをトグルさせます。開閉状態が現在の逆になる

src/main/java/com/mos1210/expandablelayout/MainActivity.kt

package com.mos1210.expandablelayout

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import net.cachapa.expandablelayout.ExpandableLayout

class MainActivity : AppCompatActivity() {

    private var isSelected = false
    private var expandableLayout: ExpandableLayout? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        expandableLayout = findViewById(R.id.expandableLayout)

        findViewById<View>(R.id.titleLayout).setOnClickListener {
            if (isSelected) {
                expandableLayout?.collapse()
            } else {
                expandableLayout?.expand()
            }
            // expandableLayout?.toggle() だけでもOK
            isSelected = !isSelected
        }
    }
}

実行結果

アプリを実行すると画面が表示されます。

レイアウトをタップするとアニメーション付きでレイアウトが開きます。

まとめ

ExpandableLayoutを使用することで、拍子抜けするほど簡単に折りたたみ対応ができました。 他にもこういう方法があるよ!などあればTwitterで教えていただければ嬉しいです。

参考