SurfaceViewを使えば、高速な描画を行うことができる。
この前に作成した、自前でアニメーションをする処理や、ゲームなどの描画にはSurfaceViewを使った方が良いだろう。
SurfaceViewのプログラミングはViewのみで描画するよりも、少しだけ複雑になる。
以下にSurfaceViewのプログラミングの例を示す。
public class MySurfaceView extends SurfaceView { private ScheduledExecutorService ses = null; private final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { ses.shutdown(); ses = null; Toast.makeText(getContext(), "surfaceDestroyed", Toast.LENGTH_SHORT).show(); } @Override public void surfaceCreated(final SurfaceHolder holder) { Toast.makeText(getContext(), "surfaceCreated", Toast.LENGTH_SHORT).show(); ses = Executors.newSingleThreadScheduledExecutor(); ses.scheduleAtFixedRate(new Runnable() { private final int ox = 100; private final int oy = 100; private final int r = 50; private int count = 0; private final Paint txtPaint = new Paint(); private final Paint figPaint = new Paint(); { txtPaint.setAntiAlias(true); txtPaint.setTextSize(12); figPaint.setAntiAlias(true); figPaint.setStyle(Style.STROKE); } @Override public void run() { final Canvas canvas = holder.lockCanvas(); if (canvas != null) { // 描画する canvas.drawColor(Color.WHITE); canvas.drawText( "" + count++, 0, txtPaint.getTextSize(), txtPaint); final double radians = Math.toRadians(count % 360); final int cx = (int)(ox + r * Math.cos(radians)); final int cy = (int)(oy + r * Math.sin(radians)); canvas.drawLine(ox, oy, cx, cy, figPaint); canvas.drawOval( new RectF(ox - r , oy - r, ox + r, oy + r), figPaint); holder.unlockCanvasAndPost(canvas); } } }, 0, 16, TimeUnit.MILLISECONDS ); } @Override public void surfaceChanged( SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub Toast.makeText(getContext(), "surfaceChanged", Toast.LENGTH_SHORT).show(); } }; /** * コンストラクタ * @param context */ public MySurfaceView(Context context) { super(context); // コールバックの登録 getHolder().addCallback(callback); } }
ポイントは、まずSurfaceViewを継承することである。
そして、getHolder()メソッドでSurfaceHolderを取得し、そこにコールバックを登録しているところである。サンプルでは83行目がその処理にあたる。
このコールバックはサーフェイスが作られたときや破壊されるときに呼ばれるので、そのタイミングで描画処理の初期化/終了処理を行う。
描画処理は別にスレッドを立てている。例ではExecutorsを使ってスレッドを取得しているが、もちろん普通のThreadクラスでかまわない。
そして、43行目からのRunnableのrun()メソッド内で、スレッドから直接Viewに描画する。
このときに必要なのはSurfaceHolderのlockCanvas()メソッドでロックされたcanvasを取得し、それに対して描画を行って、unlockCanvasAndPost()メソッドでロックを解除することである。この基本的な流れが分かれば、描画のプログラミング自体は普通のViewのものと変わらないので、色々と応用できるだろう。
Activityのプログラムは、単に上で作った自分のSurfaceViewを登録しているだけである。
public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MySurfaceView(this)); } }
サンプルは、円の中を直線が回転するプログラムである。
実行結果は以下のようになる。
[slmplayer uri=”2011/06/20110625_device.wmv”]