読者です 読者をやめる 読者になる 読者になる

techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

「Dribbbleのぬるぬる動くメニューUIのアイデア10選」からDelivery Card(FoldingCell)を試してみる

Dribbble FoldingCell Delivery Card Android

Dribbbleのぬるぬる動くメニューUIのアイデア10選という記事を見たので、実際に試してみました。

今回はこの記事の中で紹介されている「Delivery Card」を実現するためのFoldingCellを実装します。

www.youtube.com

セットアップ

Dribbbleのサイトで「Delivery Card」で検索するとトップに出てきました。

dribbble.com

ページ内にあるAndroidのリンクを押すとGithubに飛びますので、READMEを見ながらセットアップします。

と言っても、build.gradle(app)を見ながらdependenciesに一行追加してSyncするだけです。

android {
    defaultConfig {
        applicationId "techium.com.foldingcellsample"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.ramotion.foldingcell:folding-cell:1.0.1' // 追加
}

ちなみに、minSDKを17以上にしておかないと怒られます。

レイアウトファイル作成

レイアウトファイルを作成していきます。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"   ・・・6行目
    android:clipToPadding="false"  ・・・7行目
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:background="@android:color/darker_gray">

    <com.ramotion.foldingcell.FoldingCell
        xmlns:folding-cell="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/folding_cell"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        folding-cell:animationDuration="2000"
        folding-cell:backSideColor="@android:color/holo_blue_dark">
        <200b>
        <!-- ①FoldingCellの1つ目の子Viewは展開後のコンテンツ部分になる -->
        <LinearLayout
            android:id="@+id/content_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#FFFFFF"
            android:orientation="vertical"
            android:visibility="gone">  <!-- ②最初は隠しておく -->

            <!-- ③高さの合計がタイトル部分の2倍以上ないといけない -->

            <ImageView
                android:id="@+id/content_img"
                android:src="@drawable/icon"
                android:layout_marginBottom="6dp"
                android:layout_marginTop="6dp"
                android:layout_width="wrap_content"
                android:layout_height="48dp" />

            <!-- line -->
            <ImageView
                android:layout_width="match_parent"
                android:layout_marginLeft="3dp"
                android:layout_marginRight="3dp"
                android:layout_height="1dp"
                android:src="@android:color/darker_gray" />

            <TextView
                android:id="@+id/content_text1"
                android:text="Acount : seit"
                android:gravity="center_vertical"
                android:layout_marginLeft="6dp"
                android:layout_width="match_parent"
                android:layout_height="29dp"/>

            <!-- line -->
            <ImageView
                android:layout_width="match_parent"
                android:layout_marginLeft="3dp"
                android:layout_marginRight="3dp"
                android:layout_height="1dp"
                android:src="@android:color/darker_gray" />

            <TextView
                android:id="@+id/content_text2"
                android:text="自己紹介 : 米屋の息子だよ"
                android:gravity="center_vertical"
                android:layout_marginLeft="6dp"
                android:layout_width="match_parent"
                android:layout_height="29dp"/>

        </LinearLayout>

        <!-- ④FoldingCellの2つ目の子Viewは折りたたまれてる時のView(タイトル) -->    <200b>
        <FrameLayout
            android:id="@+id/title_group"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">   <!-- ⑤子Viewのheightはwrap_conentでなくてはならない -->

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:background="@android:color/holo_blue_dark">

                <ImageView
                    android:src="@drawable/icon"
                    android:layout_width="30dp"
                    android:layout_height="30dp" />    <!-- ⑥コンテンツ部はこのheightの2倍以上にしなければいけない -->

                <TextView
                    android:text="seit"
                    android:gravity="center_vertical"
                    android:layout_width="match_parent"
                    android:layout_marginLeft="6dp"
                    android:layout_height="30dp"
                    android:textColor="#FFFFFF"
                     />
            </LinearLayout>
        </FrameLayout>
        <200b>
    </com.ramotion.foldingcell.FoldingCell>
</LinearLayout>

実装にはいくつかルールがあります。
1. まず、FoldingCellの1つ目の子Viewがコンテンツ部(展開時のレイアウト)、2つ目の子Viewがタイトル部(折りたたんでいる時のレイアウト)になります。・・(①、④)
また、それぞれの子View(content_group及びtitle_group)の高さにはwrap_contentを指定しておく必要があります。
2. 画面表示時、コンテンツ部は必要ないため、android:visibility="gone"を指定しておく必要があります。・・②
3. コンテンツ部の高さの合計値は、タイトル部の高さの合計値の2倍以上に設定する必要があります。・・(③、⑥)
4. 正常にアニメーションをさせるために、6行目、7行目にそれぞれ以下の通り属性を指定しておく必要があります。

    android:clipChildren="false"
    android:clipToPadding="false"

またこのサンプルでは、折りたたみの谷となる部分にに示すような区切り線を配置していますが、 綺麗に折り目の部分に線を配置するのは知っておかないと少し面倒です。
まず1回目の展開は以下のような高さ配分になります。
f:id:uentseit:20160624234627p:plain:w200
図. 1回展開された状態

2回目以降の展開回数(ここでは2回)は以下の式にしたがって自動で計算されます。
(コンテンツ部の高さ(120) - タイトル部の高さ(30dp) * 2) / タイトル部の高さ(30dp)
高さはタイトル部の高さ(30dp)となります。
もし割り切れない場合は、さらにもう一回折りたたみ回数が追加となり、余った数値分の高さで展開となります。
f:id:uentseit:20160624235453p:plain:w200
図. 2回展開された状態

f:id:uentseit:20160624235559p:plain:w200
図. 3回展開された状態
といったようなことを考慮して、コンテンツ部の各Viewの高さ調整とを配置をしています。

また、以下のような属性値もあるので、必要に応じて設定します。

folding-cell:animationDuration="1000"  ・・・展開速度の調整
folding-cell:backSideColor="@color/bgBackSideColor"  ・・・展開中のアニメーションの色
folding-cell:additionalFlipsCount="2"  ・・・自動計算の展開回数を増やしたい場合は指定

Activity側の実装

次に、Activity側の実装を見ていきます。

package techium.com.foldingcellsample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.ramotion.foldingcell.FoldingCell;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final FoldingCell fc = (FoldingCell) findViewById(R.id.folding_cell);

        fc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fc.toggle(false);   // 展開する
            }
        });

    }
}

シンプルに、FoldingCellでonClickイベントを取得し、その中で展開を行うためのFoldingCell#toggleメソッドにfalse(展開)を引数として渡しています。

今回はこんなところでしょうか。 また他のものも試してみたいと思います。