Home > android > Androidで3D回転エフェクトをかける方法

Androidで3D回転エフェクトをかける方法


前回のエントリでAndroid SDK m5-rc14対応の電子ブックリーダを公開しました。
そこで適用した3D回転エフェクトの掛け方をご紹介します。

やりたいこと

現在表示している画面をグルっと回転させて、裏側に別の画像を表示する。

準備

グルっと回転させて、表と裏の表示を切り替えるので、表面と裏面を準備します。
レイアウトXMLはこんな感じです。

main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/container"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent">
  <ImageView android:id="@+id/front"
             android:src="@drawable/front"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent" />
  <ImageView android:id="@+id/back"
             android:src="@drawable/back"
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"
             android:visibility="gone" />
</FrameLayout>

FrameLayoutを回転させます。
その際にfrontとbackの表示を切り替えます。
初期状態はbackが非表示(gone)です。

リソースを取得
public void onCreate(Bundle icicle) {
  super.onCreate(icicle);
  setContentView(R.layout.main);
  this.mContainer = (ViewGroup) findViewById(R.id.container);
  this.frontView = (ImageView) findViewById(R.id.front);
  this.backView = (ImageView) findViewById(R.id.back);
}

これはAndroidの基本ですね。

0〜90度回転させる

まず表示面のまま90度回転させます。

float start = 0f;
float mid = 90f;
 
this.centerX = mContainer.getWidth() / 2.0f;
this.centerY = mContainer.getHeight() / 2.0f;
 
Rotate3dAnimation rot;
rot = new Rotate3dAnimation(start, mid, centerX, centerY, depth, true);
rot.setDuration(500);
rot.setAnimationListener(new DisplayNextView(mid, end, depth));
mContainer.startAnimation(rot);
Rotate3dAnimation

Rotate3dAnimationはAnimationクラスを継承した独自クラスです。
ApiDemoをそのまま使わせてもらっています。
アニメーションは、AnimationクラスのapplyTransformationメソッドが呼出されることで動作します。

void applyTransformation(float interpolatedTime, Transformation t) { ... }

interpolateTimeは0から1までの値が渡さます。
ちょっと複雑なのですが、0から1まで連続した値が渡されてapplyTransformationメソッドがよびだされ続けます。
時系列で説明するとこんな感じです。

applyTransformation(0f, t);
applyTransformation(0.2f, t);
applyTransformation(0.4f, t);
applyTransformation(0.6f, t);
applyTransformation(0.8f, t);
applyTransformation(1.0f, t);

setDurationで指定した500msの間でcallされ続けます。
この例では、0.2間隔で呼出されています。この間隔を変更したい場合は、

rot.setInterpolator(new AccelerateInterpolator());

を設定します。間隔の時間を変化しながらapplyTransformationが呼出されます。

ちょっと複雑ですが、引数のinterpolatedTimeに応じて対象を移動させたり、表示角度を変化させたりすれば、アニメーションを実装できます。
回転の場合はカメラを回転させています。

Camera camera = new Camera();
camera.rotateY(degrees);

startAnimationは、名前の通りアニメーションを開始します。

DisplayNextView

DisplayNextViewはAnimation.AnimationListenerをimplementsしたクラスです。
これはアニメーションのイベントを取得できるリスナーです。
取得できるイベントは、以下の3つ。

void onAnimationEnd()
void onAnimationRepeat()
void onAnimationStart()

今回は0度から90度までの回転アニメーションが終わると、残りの90度から180度までを回転させます。
よってonAnimationEndイベントを利用します。

90〜180度回転させる

ではonAniamtionEndで残りの回転をさせます。回転処理は基本的に今までと同じです。
Rotate3dAnimationを使います。
その前に、表示面を切り替えます。表から裏面に切り替える例を示します。

this.frontView.setVisibility(View.GONE);
this.backView.setVisibility(View.VISIBLE);

概要はこんな感じです。

private class DisplayNextView implements AnimationListener {
  public void onAnimationStart() { }
  public void onAnimationRepeat() { }
  public void onAnimationEnd() {
    mContainer.post(new Runnable() {
      frontView.setVisibility(View.GONE);
      backView.setVisibility(View.VISIBLE);
 
      Rotate3dAnimation rot;
      rot = new Rotate3dAnimation(mid, end, centerX, centerY, depth, false);
      rot.setDuration(500);
      rot.setInterpolator(new AccelerateInterpolator());
      mContainer.startAnimation(rot);
    });
  }
}

以上で3次元の回転を実装できました。

スクリーンキャスト

動作はこういった感じです。

Download

eclipseプロジェクトを公開します。ご参考にどうぞ。
rotation3d.zip

おわりに

3Dアニメーションはテクニカルで勉強になりました。
ちょっと複雑なので、いずれ誰かが簡単なライブラリを作る気もする。
でも基礎を知っていて損は無いと思った。

人体模型図

イメージはDeep anatomy @kayaprajnaからお借りしました。Special Thanx!

Source Code
package com.adamrocker.android.rotation3d;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
 
public class Rotation3D extends Activity {
  private boolean isFront = true;
  private int DURATION = 500;
  private ViewGroup mContainer;
  private ImageView frontView, backView;
  private float centerX;
  private float centerY;
 
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    this.mContainer = (ViewGroup) findViewById(R.id.container);
    this.frontView = (ImageView) findViewById(R.id.front);
    this.backView = (ImageView) findViewById(R.id.back);
  }
 
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    super.onKeyDown(keyCode, event);
    switch (keyCode) {
    case KeyEvent.KEYCODE_SPACE:
      if (isFront) {
        applyRotation(0f, 90f, 180f, 0f);
      } else {
        applyRotation(180f, 270f, 360f, 0f);
      }
      break;
    }
    return false;
  }
 
  /* startからendまでY軸回転する */
  private void applyRotation(float start, float mid, float end, float depth) {
    this.centerX = mContainer.getWidth() / 2.0f;
    this.centerY = mContainer.getHeight() / 2.0f;
 
    Rotate3dAnimation rot = new Rotate3dAnimation(start, mid, centerX, centerY,
        depth, true);
    rot.setDuration(DURATION);
    // rot.setInterpolator(new AccelerateInterpolator());
    rot.setAnimationListener(new DisplayNextView(mid, end, depth));
    mContainer.startAnimation(rot);
  }
 
  private class DisplayNextView implements AnimationListener {
    private float mid;
    private float end;
    private float depth;
 
    public DisplayNextView(float mid, float end, float depth) {
      this.mid = mid;
      this.end = end;
      this.depth = depth;
    }
 
    public void onAnimationEnd() {
      mContainer.post(new Runnable() {
        public void run() {
          if (isFront) {
            frontView.setVisibility(View.GONE);
            backView.setVisibility(View.VISIBLE);
            isFront = false;
          } else {
            frontView.setVisibility(View.VISIBLE);
            backView.setVisibility(View.GONE);
            isFront = true;
          }
 
          Rotate3dAnimation rot = new Rotate3dAnimation(mid, end, centerX,
              centerY, depth, false);
          rot.setDuration(DURATION);
          rot.setInterpolator(new AccelerateInterpolator());
          mContainer.startAnimation(rot);
        }
      });
    }
 
    public void onAnimationStart() {}
 
    public void onAnimationRepeat() {}
  }
}
関連のありそうなエントリ

Comments:0

Comment Form
Remember personal info

*
To prove that you're not a bot, enter this code
Anti-Spam Image

Trackbacks:1

Trackback URL for this entry
http://www.adamrocker.com/blog/188/android_3d_rotatoin_effect.html/trackback/
Listed below are links to weblogs that reference
Androidで3D回転エフェクトをかける方法 from throw Life
trackback from Grebin 08-10-10 (金) 10:37

grebintruber…

folo (more…)

Home > android > Androidで3D回転エフェクトをかける方法

Search
Feeds
Meta

Return to page top