[Androidアプリ開発] iOS 7 みたいなスイッチをアニメーション付きで作ってみた

2013.09.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

今回は、AndroidToggleButtondrawable を設定し、アニメーションを付けて、iOS7UISwitch みたいにしてみようと思います。
iOS7UISwitch というのは、下の画像のようなものです。

android-ios7-uiswitch

実装(drawable)

アニメーション部分を作りやすくするために、背景部分を3枚用意し、その上に ToggleButton を置きます。
まずは背景から作っていきます。

toggle_bg_gray.xml

一番下のグレーの背景を作ります。
res/drawable-xxhdpi フォルダに toggle_bg_gray.xml ファイルを新規作成します。

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

    <item
        android:bottom="6dp"
        android:top="6dp">
        <shape android:shape="rectangle" >
            <corners android:radius="18dp" />

            <solid android:color="#cccccc" />
        </shape>
    </item>

</layer-list>

toggle_bg_green.xml

下から二番目の緑の背景を作ります。
res/drawable-xxhdpi フォルダに toggle_bg_green.xml ファイルを新規作成します。

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

    <item
        android:bottom="6dp"
        android:top="6dp">
        <shape android:shape="rectangle" >
            <corners android:radius="18dp" />

            <solid android:color="#43d551" />
        </shape>
    </item>

</layer-list>

toggle_bg_white.xml

下から三番目の真っ白の背景を作ります。
res/drawable-xxhdpi フォルダに toggle_bg_white.xml ファイルを新規作成します。

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

    <item
        android:bottom="6dp"
        android:top="6dp">
        <shape android:shape="rectangle" >
            <corners android:radius="18dp" />

            <solid android:color="#ffffff" />

            <stroke
                android:width="3dp"
                android:color="#00000000" />
        </shape>
    </item>

</layer-list>

toggle_btn.xml

ボタン部分を作ります。
res/drawable-xxhdpi フォルダに toggle_btn.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="3dp">
        <shape android:shape="oval" >
            <gradient
                android:centerColor="#99000000"
                android:endColor="#00000000"
                android:gradientRadius="30"
                android:startColor="#99000000"
                android:type="radial" />
        </shape>
    </item>
    <item android:bottom="4dp"
          android:left="2dp"
          android:right="2dp"
          android:top="4dp">
        <shape android:shape="oval" >
            <size android:height="32dp" android:width="32dp" />
            <solid android:color="#ffffff" />
        </shape>
    </item>
</layer-list>

activity_main.xml

ここまでで、表示するパーツが一通りそろったので res/layout フォルダの activity_main.xml ファイルを修正して、
背景3枚とトグルボタンを配置します。

<RelativeLayout 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:background="#ffffff"
    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" >

    <FrameLayout
        android:layout_width="58dp"
        android:layout_height="48dp" >

        <View
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/toggle_bg_gray" />

        <View
            android:id="@+id/tglBgGreen"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/toggle_bg_green" />

        <View
            android:id="@+id/tglBgWhite"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/toggle_bg_white" />

        <ToggleButton
            android:id="@+id/tglBtn"
            android:layout_width="58dp"
            android:layout_height="wrap_content"
            android:background="@null"
            android:button="@drawable/toggle_btn"
            android:checked="true"
            android:textOff=""
            android:textOn="" />
    </FrameLayout>

</RelativeLayout>

実装(アニメーション)

ここからは、アニメーション部分を作っていきます。

toggle_bg_green_off.xml

スイッチオフのときの緑背景のアニメーションを作ります。
res フォルダに新たに anim フォルダを作成して、その中に toggle_bg_green_off.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="150"
    android:fillAfter="true"
    android:fromAlpha="1"
    android:toAlpha="0" />

toggle_bg_green_on.xml

スイッチオンのときの緑背景のアニメーションを作ります。
res/anim フォルダに toggle_bg_green_on.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="150"
    android:fillAfter="true"
    android:fromAlpha="0"
    android:toAlpha="1" />

toggle_bg_white_off.xml

スイッチオフのときの白背景のアニメーションを作ります。
res/anim フォルダに toggle_bg_white_off.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="100"
    android:fromXScale="0"
    android:fromYScale="0"
    android:pivotX="80%"
    android:pivotY="50%"
    android:startOffset="50"
    android:toXScale="1"
    android:toYScale="1" />

toggle_bg_white_on.xml

スイッチオンのときの白背景のアニメーションを作ります。
res/anim フォルダに toggle_bg_white_on.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="100"
    android:fillAfter="true"
    android:fromXScale="1"
    android:fromYScale="1"
    android:pivotX="80%"
    android:pivotY="50%"
    android:toXScale="0"
    android:toYScale="0" />

toggle_btn_off.xml

スイッチオフのときのボタン部分のアニメーションを作ります。
res/anim フォルダに toggle_btn_off.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator" >

    <scale
        android:duration="50"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="100%"
        android:pivotY="50%"
        android:toXScale="1.1"
        android:toYScale="1.0" />
    <scale
        android:duration="100"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="100%"
        android:pivotY="50%"
        android:startOffset="50"
        android:toXScale="0.909"
        android:toYScale="1.0" />

    <translate
        android:duration="150"
        android:fromXDelta="38%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />

</set>

set を使用すると複数のアニメーションを使用することができます。

toggle_btn_on.xml

スイッチオンのときのボタン部分のアニメーションを作ります。
res/anim フォルダに toggle_btn_on.xml ファイルを新規作成します。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator" >

    <scale
        android:duration="50"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="0%"
        android:pivotY="50%"
        android:toXScale="1.1"
        android:toYScale="1.0" />
    <scale
        android:duration="100"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="0%"
        android:pivotY="50%"
        android:startOffset="50"
        android:toXScale="0.909"
        android:toYScale="1.0" />

    <translate
        android:duration="150"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="38%"
        android:toYDelta="0%" />

</set>

MainActivity.java

最後に MainActivity.java を修正して、アニメーションの処理を追加します。

package jp.classmethod.sampletogglebuttonanim;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;

public class MainActivity extends Activity {

	private View mTglBgWhite;
	private View mTglBgGreen;
	private ToggleButton mTglBtn;

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

		mTglBgWhite = (View) findViewById(R.id.tglBgWhite);
		mTglBgGreen = (View) findViewById(R.id.tglBgGreen);
		mTglBtn = (ToggleButton) findViewById(R.id.tglBtn);

		if (mTglBtn.isChecked()) {
			animOn(true);
		} else {
			animOff(true);
		}

		mTglBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (isChecked) {
					animOn(false);
				} else {
					animOff(false);
				}
			}
		});
	}

	private void animOn(boolean durationZero) {
		Animation btnAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_btn_on);
		Animation bgWhiteAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_bg_white_on);
		Animation bgGreenAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_bg_green_on);

		if (durationZero) {
			btnAnim.setDuration(0);
			bgWhiteAnim.setDuration(0);
			bgGreenAnim.setDuration(0);
		}

		mTglBtn.startAnimation(btnAnim);
		mTglBgWhite.startAnimation(bgWhiteAnim);
		mTglBgGreen.startAnimation(bgGreenAnim);
	}

	private void animOff(boolean durationZero) {
		Animation btnAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_btn_off);
		Animation bgWhiteAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_bg_white_off);
		Animation bgGreenAnim = AnimationUtils.loadAnimation(
				getApplicationContext(), R.anim.toggle_bg_green_off);

		if (durationZero) {
			btnAnim.setDuration(0);
			bgWhiteAnim.setDuration(0);
			bgGreenAnim.setDuration(0);
		}

		mTglBtn.startAnimation(btnAnim);
		mTglBgWhite.startAnimation(bgWhiteAnim);
		mTglBgGreen.startAnimation(bgGreenAnim);
	}

}

動作確認

では、動かしてみます。

android-ios7-uiswitch_anim_01

android-ios7-uiswitch_anim_02

android-ios7-uiswitch_anim_03

はい。できました。
ToggleButton に drawable をあててアニメーションを付け加えただけなので、フリックしても反応しないなど、挙動が異なるところもありますが、
今回はここまでということで。。

ではでは。