[Android 開発] View でアニメーション描画

Posted by
ぴろり
Posted at
2015/02/14 11:28
Trackbacks
関連記事 (0)
Post Comment
コメントできます
Category
開発メモ カテゴリ
カバーイメージ

 SurfaceView を使用すれば、高速なグラフィックス描画が可能なことが判りましたが、View でも同じことができないか試してみました。
 結論から言えば、「動作はするが、なめらかアニメーションの描画には向かない」ということが判りました。

このエントリーをはてなブックマークに追加  

スクラップ帳 » Android アプリ開発 Tips ~ グラフィックスの描画

 Android アプリを開発する際の小技まとめ。画面へのグラフィックス描画などの覚書きを網羅して、必要な機能をコピー&ペーストで再利用できるようにします。

  1. グラフィックスの描画 ~ View 編 2015/02/09
  2. グラフィックスの描画 ~ SurfaceView 編 2015/02/10
  3. View でアニメーション描画 2015/02/14 今ココ

概要

  1. View クラスを継承して、MyView クラスを宣言します
  2. 加えて、MyView クラスは、Runnable インタフェースを実装します
  3. MyView#onDraw を override して、グラフィックスを描画をします
  4. MyView#run を implement して、画面を更新し続けます

 手順 4 において、単純に invalidate() を呼び出すとエラーになります。MyView の描画は、自分自身のメイン スレッドからしか行えないためで、そのままでは MyView#run で走っている別スレッドからは MyView の描画を更新できません。そこで、Handler でメッセージ キューを作成して、メイン スレッド宛てに描画するようメッセージを送信しています。


Fig.1 スクリーンショット

ソースコード

package com.example.helloworld;

import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public class MainActivity extends ActionBarActivity
{
    private Thread mThread;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView( new MyView( this ));
    }

    public void onDestroy(){
        super.onDestroy();

        mThread.interrupt();
    }


    private class MyView extends View implements Runnable
    {
        private Handler mHandler;

        public MyView( Context context ) {
            super( context );

            mHandler =  new Handler();
            mThread = new Thread(this);
            mThread.start();
        }

        private Paint mPaint = null;
        private float mScreenWidth, mScreenHeight;

        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged( w,h, oldw,oldh );

            mPaint = new Paint();
            mScreenWidth = w;
            mScreenHeight = h;
        }

        float vx = 5, vy = 5;
        float xOffset = 100, yOffset = 100;
        float radius = 50;
        long now = System.currentTimeMillis(); // FPS 計測用

        protected void onDraw( Canvas canvas ) {
            super.onDraw(canvas);

            if (xOffset <= radius || mScreenWidth - radius <= xOffset)
                vx = -vx;
            if (yOffset <= radius)
                vy = -vy;
            if (mScreenHeight - radius <= yOffset) {
                yOffset = mScreenHeight - radius;
                vy = -70;
            }

            xOffset += vx;
            yOffset += vy;
            vy += 5;

            mPaint.setColor( Color.GREEN );

            canvas.drawColor(Color.argb(64, 0,0,0));
            canvas.drawCircle(xOffset, yOffset, radius, mPaint);

            long now_next = System.currentTimeMillis();
            canvas.drawText(String.format("%6.2f", 1000/(float)(now_next - now)), 30, yOffset, mPaint);
            now = now_next;
        }

        public void run() {
            while( true ) {
                mHandler.post(new Runnable() {
                    public void run() {
                        invalidate();
                    }
                });
            }
        }
    }
}

解説

83 行目
 メッセージ キューとして Handler オブジェクトを生成している。キューは、このスレッド(描画スレッド)にバインドされている。
57~81 行目
 画面内をボールが跳ね回るアニメーション。
83~91 行目
 メッセージ キューに、画面を更新するための Runnable インスタンスをポストしている。これによって、描画スレッドで invalidate() が実行されて、画面が更新される。

 FPS 値が一桁ということもなく、SurfaceView を使用した場合と遜色なく高速に動作しますが、ただ、不意に動作がカクカクすることがあって、なめらかなアニメーション動作を安定して続けることができません。上記のソースコードでは、MyView.onDraw 内で canvas に直接描画していますが、オフ スクリーン バッファに描画してから、最後に canvas に書き出すようにしたところ、更にカクつきが酷くなりました。テーブルゲームなどのアクション性を要求されない描画では十分ですが、「不意にカクつく」という点はゲームなどでは許容できないこともありますので、やはりそこは SurfaceView を使った方が良いようです。

参考リンク

このエントリーをはてなブックマークに追加  


この記事を読んだ人はこんな記事も読んでいます記事リコメンデーションについて

カバー画像:[Android 開発] グラフィックスの描画 ~ SurfaceView 編

関連記事/トラックバック

関連記事/トラックバックはまだありません

この記事にトラックバックを送るには?

コメントを投稿する

 
 (必須, 匿名可, 公開, トリップが使えます)
 (必須, 匿名可, 非公開, Gravatar に対応しています)
 (必須)
スパム コメント防止のため「投稿確認」欄に ランダムな数字 CAPTCHAについて を入力してから送信してください。お手数ですがご協力のほど宜しくお願いいたします。