ぐるぐるまわるボタン - ReDo

2010年9月30日

ぐるぐるまわるボタン

GDD2010jpで見た、押すとぐるぐるまわるボタンが面白かったので実装してみました。

apkファイル。
http://greety.sakura.ne.jp/redo/apps/GuruguruButton.apk
Eclipseプロジェクトなソース。
http://greety.sakura.ne.jp/redo/apps/GuruguruButton.zip

negikegani1.png
  • translateアニメーションとrotateアニメーションを組み合わせます。ImageViewに両方のアニメーションを同時に適用させるとpivotX, pivotYで示す回転中心がおかしなことになるので、Layoutを別にして、それぞれにアニメーションを適用させます。
  • 回転中心のpivotX,pivotYが画像の中心50%から若干ずれているのは画像のつくりに因ります。
  • ボタンを1回押されたらアニメーションが終わるまではsetClickable(false)して連打されない様にしています。
  • 音がなるのはオマケです。気にしないでください。

round_left.xml 左回転

<?xml version="1.0" encoding="utf-8"?>
<set
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/linear_interpolator">
	<rotate
		android:fromDegrees="0"
		android:toDegrees="-1080"
		android:pivotX="35%"
		android:pivotY="50%"
		android:startOffset="0"
		android:duration="1500" />
</set>

round_right.xml 右回転

<?xml version="1.0" encoding="utf-8"?>
<set
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/linear_interpolator">
	<rotate
		android:fromDegrees="0"
		android:toDegrees="1080"
		android:pivotX="65%"
		android:pivotY="50%"
		android:startOffset="0"
		android:duration="1500" />
</set>

trans_left.xml 左移動

<?xml version="1.0" encoding="utf-8"?>
<set
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/accelerate_interpolator">
	<translate
		android:fromXDelta="0%"
		android:fromYDelta="0"
		android:toXDelta="-200%"
		android:toYDelta="0"
		android:startOffset="0"
		android:duration="2000" />
</set>

trans_right.xml 右移動

<?xml version="1.0" encoding="utf-8"?>
<set
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/accelerate_interpolator">
	<translate
		android:fromXDelta="0%"
		android:fromYDelta="0"
		android:toXDelta="200%"
		android:toYDelta="0"
		android:startOffset="0"
		android:duration="2000" />
</set>

ソースはこんな感じ。

package youten.redo.guruguru;

import android.app.Activity;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;

/**
 * ぐるぐるボタン テストアプリ メインActivity
 */
public class GuruguruActivity extends Activity {
	/** ハンドら */
	private Handler handler = null;
	/** ogg:ねぎですか?けがにですか? */
	private static final int SOUND_NEGI2KEGANI2 = 0;
	/** ogg:ねぎですか */
	private static final int SOUND_NEGI4 = 1;
	/** ogg:けがにですか */
	private static final int SOUND_KEGANI4 = 2;
	/** ogg:サウンド最大数 */
	private static final int SOUND_MAX = 3;

	/** SoundPool */
	private SoundPool soundPool = null;
	/** SoundIDs */
	private int[] soundIDs = null;
	/** 右回転アニメーション */
	private Animation roundRightAnim = null;
	/** 右移動アニメーション */
	private Animation transRightAnim = null;
	/** 左回転アニメーション */
	private Animation roundLeftAnim = null;
	/** 左移動アニメーション */
	private Animation transLeftAnim = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		handler = new Handler();

		// soundPoolプリロード
		soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
		if(soundPool != null)
		{
			soundIDs = new int[SOUND_MAX];
			soundIDs[SOUND_NEGI2KEGANI2] = soundPool.load(this, R.raw.negi2kegani2, 0);
			soundIDs[SOUND_NEGI4] = soundPool.load(this, R.raw.negi4, 0);
			soundIDs[SOUND_KEGANI4] = soundPool.load(this, R.raw.kegani4, 0);
		}

		// アニメーション事前ロード
		roundRightAnim = AnimationUtils.loadAnimation(this, R.anim.round_right);
		transRightAnim = AnimationUtils.loadAnimation(this, R.anim.trans_right);
		transRightAnim.setAnimationListener(new AnimationListener()
		{
			public void onAnimationStart(Animation animation) {
				findViewById(R.id.negi_image).setClickable(false);
			}
			public void onAnimationEnd(Animation animation) {
				findViewById(R.id.negi_image).setClickable(true);
			}
			public void onAnimationRepeat(Animation animation) {
			}
		});
		roundLeftAnim = AnimationUtils.loadAnimation(this, R.anim.round_left);
		transLeftAnim = AnimationUtils.loadAnimation(this, R.anim.trans_left);
		transLeftAnim.setAnimationListener(new AnimationListener()
		{
			public void onAnimationStart(Animation animation) {
				findViewById(R.id.kegani_image).setClickable(false);
			}
			public void onAnimationEnd(Animation animation) {
				findViewById(R.id.kegani_image).setClickable(true);
			}
			public void onAnimationRepeat(Animation animation) {
			}
		});

		// Buttonイベントハンドラ:ねぎ
		findViewById(R.id.negi_image).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				// 画像の下のFrameLayoutに右移動アニメーションを適用。
				findViewById(R.id.negi_frame).startAnimation(transRightAnim);
				// 画像に右回転アニメーションを適用。
				v.startAnimation(roundRightAnim);
				// ねぎですか
				soundpool(SOUND_NEGI4);
			}
		});

		// Buttonイベントハンドラ:けがに
		findViewById(R.id.kegani_image).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				// 画像の下のFrameLayoutに左移動アニメーションを適用。
				findViewById(R.id.kegani_frame).startAnimation(transLeftAnim);
				// 画像に左回転アニメーションを適用。
				v.startAnimation(roundLeftAnim);
				// けがにですか
				soundpool(SOUND_KEGANI4);
			}
		});

	}

	@Override
	protected void onResume() {
		super.onResume();
		// 直接書いたら時々音がならなかったので500msディレイを入れた。よくわからない。
		handler.postDelayed(new Runnable()
		{
			public void run()
			{
				// ねぎですか?けがにですか?
				soundpool(SOUND_NEGI2KEGANI2);
			}
		}, 500);
	}

	/**
	 * 音を鳴らす。
	 * @param id 音ID
	 */
	private void soundpool(int id)
	{
		// どっからでも呼べる様に一応チェックを行う。過剰かも。
		if( (soundPool != null) && (soundIDs != null) )
		{
			if(id < soundIDs.length)
			{
				// 意外と音量が大きかったので50,50に落とす。
				soundPool.play(soundIDs[id], 50, 50, 1, 0, 1);
			}
		}
	}
}

コメントする