うさがにっき

読書感想文とプログラムのこと書いてきます

Androidでアニメーション付きのカードレイアウトの作り方

概要

こんな感じのカードレイアウトを作る
f:id:tiro105:20140620174313p:plain

詳細

ListViewを使って作れば、Viewをそこまで考えなくても作れる
ListView部分

public class CardListFragment extends ListFragment {

    final static int[] sImages = { R.drawable.image1, R.drawable.image2,
            R.drawable.image3, R.drawable.image4, R.drawable.image5,
            R.drawable.image6, R.drawable.image7, R.drawable.image8 };

    final static String[] sTitles = { "Metallic", "Honeycomb", "Normal", "Gopher",
            "Rabbit", "HPROH", "Bar Android", "Coffee" };

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        ListView listView = getListView();
        // 区切り線を消す
        listView.setDivider(null);
        // スクロールバーを表示しない
        listView.setVerticalScrollBarEnabled(false);
        // カード部分をselectorにするので、リストのselectorは透明にする
        listView.setSelector(android.R.color.transparent);

        Item[] data = new Item[sImages.length];
        for (int i = 0; i < sImages.length; i++) {
            data[i] = new Item(sTitles[i], sImages[i]);
        }

        setListAdapter(new CustomAdapter(getActivity(),
        		R.layout.card_item1, data));
    }

区切り線を消し、リストのselectorを透明にしておく(カード部分でselectorは実装するため)

Adapter部分

    public static class CustomAdapter extends ArrayAdapter<Item> {

        LayoutInflater mInflater;
        int mResId;
        int mAnimatedPosition = ListView.INVALID_POSITION;

        public CustomAdapter(Context context, int resource, Item[] data) {
            super(context, 0, data);
            mResId = resource;
            mInflater = LayoutInflater.from(context);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = mInflater.inflate(mResId, parent, false);
            }

            Item item = getItem(position);

            ImageView iv = (ImageView) convertView.findViewById(R.id.image);
            iv.setImageResource(item.imageResId);

            TextView tv = (TextView) convertView.findViewById(R.id.title);
            tv.setText(item.title);

            // まだ表示していない位置ならアニメーションする
            if (mAnimatedPosition < position) {
                // XMLからアニメーターを作成
                Animator animator = AnimatorInflater.loadAnimator(getContext(),
                        R.animator.card_slide_in);
                // アニメーションさせるビューをセット
                animator.setTarget(convertView);
                // アニメーションを開始
                animator.start();
                mAnimatedPosition = position;
            }

            return convertView;
        }
    }


カードのレイアウト

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/card_item_bg2"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="@dimen/thumbnail_height"
            android:contentDescription="@string/thumbnail"
            android:scaleType="centerCrop" />

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="@dimen/title_height"
            android:gravity="center_vertical"
            android:paddingLeft="8dp"
            android:paddingRight="8dp" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#cccccc" />
</LinearLayout>

上左右にpaddingを設定することによりカードっぽく見せている。
カードの背景にはdrawableを指定することにより、selectorを実装している。

selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#f2f2f2"/>
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#ffffff"/>
        </shape>
    </item>
</selector>


まだ表示していないカードを表示するときにはアニメーション付きで表示する。
この部分

            // まだ表示していない位置ならアニメーションする
            if (mAnimatedPosition < position) {
                // XMLからアニメーターを作成
                Animator animator = AnimatorInflater.loadAnimator(getContext(),
                        R.animator.card_slide_in);
                // アニメーションさせるビューをセット
                animator.setTarget(convertView);
                // アニメーションを開始
                animator.start();
                mAnimatedPosition = position;
            }


アニメーションの指定

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- X軸まわりの回転 -->
    <objectAnimator
        android:duration="500"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:propertyName="rotationX"
        android:valueFrom="30"
        android:valueTo="0" />

    <!-- 透明度 -->
    <objectAnimator
        android:duration="300"
        android:propertyName="alpha"
        android:valueFrom="0.0"
        android:valueTo="1.0" />

    <!-- 下から上にスライド -->
    <objectAnimator
        android:duration="500"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:propertyName="translationY"
        android:valueFrom="600"
        android:valueTo="0" />

</set>