ViewFlipper によるアニメーション付き画面切り替え

iPhone や Android などの新しいスマートフォンでは美しい UI も魅力の一つです。

クールなかっこいい印象を出すためには、画面を切り替えるときに、スイッチのオン・オフのように機械的に切り替わるのではなく、スライドしたり、ズームしたりという効果をいれた方が良い場合も少なくありません。

いわゆる トゥイーン・アニメーション (Tween Animation) というものです。これに対して映画のように画像を切り替えてみせるのはフレームアニメーション (Frame Animation) といいます。

ここでは Android がもつ ViewFlipper というウィジェットを利用して、画面のスライド・アニメーションを行う方法を示します。

ViewFlipper サンプルプログラムの動作

ここで作るアニメーションは次のようなものです。

まず、"Hello!" という文字とボタンがひとつある画面があります。

ViewFlipper

このボタンをクリックすると、アニメーションが始まり、今まで表示されていた画面が左側にスライドして消えていきます。と、同時に右側から新しい画面がスライドインしてきます。

ViewFlipper ViewFlipper ViewFlipper

そして最終的に右側から入ってきた画面が全面に表示されます。

ViewFlipper

この状態からボタンを押すと、今度は左側から元の画面がスライドインしてきて、現在の画面が右側にスライドしていきます。

このようなアニメーション効果をどのように設定するのか、具体的なコード例をみていきます。

ViewFlipper のコード例

XML によるアニメーションとレイアウトの設定

Tween アニメーションは res/anim ディレクトリ内の XML ファイルで定義できます。コンパイル後は Animation オブジェクトとして扱えます。

res/anim/filename.xml とすると、プログラムからは R.anim.filename としてアクセスできます。

具体例として以下の効果を設定します。

left_in.xml

500ms かけて左側からスライドして入ってきます。

<?xml version="1.0" encoding="utf-8"?>
<set 
  xmlns:android="http://schemas.android.com/apk/res/android">
  <translate
    android:fromXDelta="-100%p"
    android:toXDelta="0"
    android:duration="500"/>
</set>

left_out.xml

500ms かけて左側へスライドして出ていきます。

<?xml version="1.0" encoding="utf-8"?>
<set 
  xmlns:android="http://schemas.android.com/apk/res/android">
  <translate
    android:fromXDelta="0"
    android:toXDelta="-100%p"
    android:duration="500"/>
</set>

right_in.xml

500ms かけて右側から入ってきます。

<?xml version="1.0" encoding="utf-8"?>
<set 
  xmlns:android="http://schemas.android.com/apk/res/android">
  <translate
    android:fromXDelta="100%p"
    android:toXDelta="0"
    android:duration="500"/>
</set>

right_out.xml

500ms かけて右側に出ていきます。

<?xml version="1.0" encoding="utf-8"?>
<set 
  xmlns:android="http://schemas.android.com/apk/res/android">
  <translate
    android:fromXDelta="0"
    android:toXDelta="100%p"
    android:duration="500"/>
</set>

res/layout/main.xml は次のとおりです。この中で、 ViewFlipper に LinearLayout を二つ含めていることに注意してください。 そして、それぞれの LinearLayout のなかでは TextView で文字を表示し、その下にボタンを配置しています。

<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/flipper"
  android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_height="match_parent" 
    android:layout_width="match_parent">
<TextView  
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:text="Hello!"
    android:textSize="30sp"
    />
<Button
  android:id="@+id/next_button"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="Next"/>
</LinearLayout>
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
<TextView  
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:text="World!"
    android:textSize="30sp"
    />
<Button
  android:id="@+id/back_button"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="Back"/>
</LinearLayout>
</ViewFlipper>

以上のリソースを作成した上で、次のようにします。

package com.keicode.android.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ViewFlipper;

public class ViewFlipperTest1 extends Activity 
    implements OnClickListener {

  ViewFlipper viewFlipper;
  Button nextButton;
  Button backButton;
  
  Animation inFromRightAnimation;
  Animation inFromLeftAnimation;
  Animation outToRightAnimation;
  Animation outToLeftAnimation;
  
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        findViews();
        setListeners();
        setAnimations();
    }
  
  protected void findViews(){
    nextButton = (Button)findViewById(R.id.next_button);
    backButton = (Button)findViewById(R.id.back_button);
    viewFlipper = (ViewFlipper)findViewById(R.id.flipper);
  }
  
  protected void setListeners(){
    nextButton.setOnClickListener(this);
    backButton.setOnClickListener(this);
  }
  
  protected void setAnimations(){    
    inFromRightAnimation = 
      AnimationUtils.loadAnimation(this, R.anim.right_in);
    inFromLeftAnimation = 
      AnimationUtils.loadAnimation(this, R.anim.left_in);
    outToRightAnimation = 
      AnimationUtils.loadAnimation(this, R.anim.right_out);
    outToLeftAnimation = 
      AnimationUtils.loadAnimation(this, R.anim.left_out);
  }

  @Override
  public void onClick(View v) {
    switch(v.getId()){
    case R.id.next_button:
      viewFlipper.setInAnimation(inFromRightAnimation);
      viewFlipper.setOutAnimation(outToLeftAnimation);
      viewFlipper.showNext();
      break;
    case R.id.back_button:
      viewFlipper.setInAnimation(inFromLeftAnimation);
      viewFlipper.setOutAnimation(outToRightAnimation);
      viewFlipper.showPrevious();
      break;
    }
    
  }
    
}

ポイントはまず、アニメーションを AnimationUtils.loadAnimation で取得している点です。 アニメーションリソースから Animation オブジェクトを取得するには、このメソッドを用いると便利です。

ここではボタンのクリックイベントリスナーはこのアクティビティ自身に設定しています。onClickメソッドにて、クリックされたボタンを判別して、アニメーションの設定をしています。

ViewFlipper の setInAnimationsetOutAnimation で入ってくる View、出て行く View に対するアニメーションの設定を行います。

最初の画面から切り替え後の画面に行くときは showNext メソッドを、 切り替え後の画面から元の画面に戻るときは showPrevious メソッドを呼びます。

ちなみに、ここでは ViewFlipper の子要素が LinearLayout 二つだけだったので、「元の画面」「次の画面」を showNext, showPrevious で行ったり来たりしていましたが、 ViewFlipper の子要素が3個以上でも構いません。そのときは showNext は次の要素へ、 showPrevious は前の子要素へ移動と考えます。

コードによるアニメーションの設定

では同じことを、アニメーションリソースを用いないで行ってみます。

状況に応じてアニメーション効果を微妙に変化させる場合等は、リソースファイルで設定することが難しい場合もあり、その場合はコードでアニメーション効果を作ることを検討すると良いでしょう。

プログラムの全体的な構成は同様ですので、変更点だけ記述します。

  ...
  protected void setAnimations(){
    inFromRightAnimation = getInFromRightAnimation();
    inFromLeftAnimation = getInFromLeftAnimation();
    outToLeftAnimation = getOutToLeftAnimation();
    outToRightAnimation = getOutToRightAnimation();    
  }

  ...
  
  private Animation getInFromRightAnimation() {
    Animation anim = new TranslateAnimation(
      Animation.RELATIVE_TO_PARENT, 1.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f);
    anim.setDuration(500);
    anim.setInterpolator(new AccelerateInterpolator());
    return anim;
  }
  
  private Animation getOutToLeftAnimation() {
    Animation anim = new TranslateAnimation(
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, -1.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f);
    anim.setDuration(500);
    anim.setInterpolator(new AccelerateInterpolator());
    return anim;
  }
  
  private Animation getInFromLeftAnimation() {
    Animation anim = new TranslateAnimation(
      Animation.RELATIVE_TO_PARENT, -1.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f);
    anim.setDuration(500);
    anim.setInterpolator(new AccelerateInterpolator());
    return anim;
  }
  
  private Animation getOutToRightAnimation() {
    Animation anim = new TranslateAnimation(
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 1.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f,
      Animation.RELATIVE_TO_PARENT, 0.0f);
    anim.setDuration(500);
    anim.setInterpolator(new AccelerateInterpolator());
    return anim;
  }
  
}

変更があるのは setAnimations メソッド内のみです。それに加え、四つのアニメーション定義用のメソッドを追加しています。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門