【Android】Canvasを使ってルーレットを作る② - Animationクラスとフリックイベント -

今回は前回作成したルーレット板にアニメーションを付けてくるくる回してみる部分です。

Animationクラスを継承したArcAnimationからRouletteViewのパラメータを調整しながらonDrawを何度も呼ぶという処理です。

実装

ArcAnimationクラスのソースコード

import android.view.animation.Animation;
import android.view.animation.Transformation;

public class ArcAnimation extends Animation {

    int base = 20;

    int count = 0;

    private MainActivity.RouletteView rouletteView;

    public ArcAnimation(MainActivity.RouletteView rouletteView) {
        this.rouletteView = rouletteView;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation transformation) {
        count++;

        int move = base - (count / 25);
        if(move < 0){
            move = 0;
        }

        rouletteView.addPos(move);
        rouletteView.requestLayout();

        if(move == 0){
            cancel();
            rouletteView.setIsAnimation(false);
        }
    }
}

メンバ変数のbaseはパネルを移動させる初期値です。つまりルーレット始動直後は20℃ずつ回転します。

メンバ変数のcountはアニメーションの回数です。このカウンタによりだんだんと回転速度を遅くする調整をします。

applyTransformation()がアニメーションのキモで、引数として渡されるinterpolatedTimeに0.0f-1.0fの範囲でアニメーションの進行値が入ってきます。が、今回はcountの値により制御しているので、この値は使用していません。

上記を見てもらうと分かると思いますが、25回アニメーションしたらbaseの値を少し下げたものをmoveする値としてRouletteViewにセットしています。

MainActivity.RouletteViewクラスのソースコード(変更点)

int pos;

public void addPos(int move) {
    pos += move;
}

メンバ変数「pos」とposの加算メソッドを追加します。

posの値によって移動する角度を決めます。

// パネルの描画
for (int i = 0; i < num; i++) {
    paint.setColor(colors[i]);
    canvas.drawArc(rectF, (i * angle) + pos, angle, true, paint);
}

draArcの第一引数(開始位置)にposを加算します。

// テキストの描画
for (int j = 0; j < num; j++) {
    int intTextAngle;
    if(j == 0) {
        intTextAngle = angle / 2 + pos;
    } else{
        intTextAngle = angle;
    }
    canvas.rotate(intTextAngle, xc, yc);
    canvas.drawText(testStrings[j], xc + 100, yc + 20, textPaint);
}

テキストの方もposを加算します。ここで注意なのがposを加算するテキストは初回だけです。

MainActivityクラスのソースコード

最後にアニメーションの開始処理を作成します。

画面をフリックしたらルーレットが回るというUIにしたいと思います。

// タッチイベントを処理するためのインタフェース
private GestureDetector gestureDetector;

// タッチイベント
@Override
public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

// タッチイベントのリスナー
private final GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {
    // フリックイベント
    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
        if(!rouletteView.isAnimation) {
            // アニメーション開始
            rouletteView.setIsAnimation(true);
            animation = new ArcAnimation(rouletteView);
            animation.setDuration(10000);
            rouletteView.startAnimation(animation);
        }
        return false;
    }
};

フリックイベントにはSimpleOnGestureListenerを使用します。

メンバ変数のonGestureListenerにSimpleOnGestureListenerを登録しておき、ActivityのonTouchEventから呼び出すと言う流れです。

SimpleOnGestureListenerのonFling()メソッドではアニメーションクラスを生成します。

setDurationはアニメーションの時間をミリ秒でセットします。今回はルーレットが止まるまでなのでとりあえず10秒を設定しておきます。(この設定がないと動きません)

startAnimationメソッドを生成したアニメーションクラスを引数に渡して投げてやればルーレットが回転します。

実行結果

このルーレットは何回回しても一定の角度を移動したら止まりますが、applyTransformationで乱数を使って調整することで、どこで止まるか分からないドキドキルーレットができそうです。

サンプルアプリ

ソースコードを以下にアップしておきました。

https://github.com/s-watanabe-apps/android-roulette

また、ここまで作成した物に少し機能を付け加えてリリースしたアプリが以下になります。

※パッケージ名が違いますが気にしないでください。

https://play.google.com/store/apps/details?id=swapp.com.roulette

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)