前回作成した自前のアニメーションを応用してみよう。
画面にタッチした点を中心に円の半径が次第に大きくなっていくアニメーションを考えてみることにする。そして、タッチしたら次々と円が描かれて行くようにする。
まず、複数の円の状態を管理しておくためのクラスを作っておくと便利である。
そこで以下のようなクラスを作った。
Mover.java
//移動物体を表すクラス public class Mover { public final int orgX; public final int orgY; public final int maxSize; private int size = 0; /** * (x1,y1)(x2,y2)間の距離を求める * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private int calcDistance(int x1,int y1, int x2, int y2){ return (int)Math.floor(Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2))); } /** * コンストラクタ * @param x * @param y * @param screenWidth * @param screenHeight */ public Mover(int x, int y, int screenWidth, int screenHeight ){ this.orgX = x; this.orgY = y; // タッチされた点と画面端の点の最大の距離を求める maxSize = Math.max(calcDistance(0, 0, orgX, orgY), Math.max(calcDistance(screenWidth,0, orgX, orgY), Math.max(calcDistance(screenWidth, screenHeight, orgX, orgY), calcDistance(0, screenHeight, orgX, orgY) ))); } public int getSize(){ return size; } public void move(){ size += 2; } public boolean outOfMaxSize(){ return maxSize < size; } }
そして、カスタムビュークラスで、先ほど作ったMoverクラスを次のように使う。
public class MyView extends View { private static int MAX_MOVER = 200; private final LinkedList<Mover> list = new LinkedList<Mover>(); private final Runnable task = new Runnable() { @Override public void run() { synchronized (list) { for( int i=list.size()-1; 0<=i; i--){ Mover m = list.get(i); m.move(); // 画面の表示範囲の外に出たらRemoveする if(m.outOfMaxSize()){ list.remove(i); Log.d("mover","mover removed"); } } } // 画面を更新する postInvalidate(); } }; private ScheduledExecutorService ses; /** * コンストラクタ * @param context */ public MyView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint p = new Paint(); p.setColor(Color.CYAN); p.setStrokeWidth(0.5f); p.setStyle(Style.STROKE); p.setAntiAlias(true); synchronized (list) { for(Mover m : list){ canvas.drawCircle(m.orgX, m.orgY, m.getSize(), p); } } } @Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_DOWN || event.getAction()==MotionEvent.ACTION_MOVE){ synchronized (list) { if( list.size() < MAX_MOVER ){ list.add( new Mover( (int)event.getX(), (int)event.getY(), getWidth(), getHeight())); } } return true; } return super.onTouchEvent(event); } public void onResume(){ ses = Executors.newSingleThreadScheduledExecutor(); ses.scheduleAtFixedRate(task, 0, 100, TimeUnit.MILLISECONDS); } public void onPause(){ ses.shutdown(); ses = null; } }
9行目の、100ミリ秒ごとに定期的に呼ばれるメソッドの中で現在描画している円の大きさを増やしている。
55行目で、円を全て描画している。
64行目で、画面上でタッチ、またはムーブをしたときに新しい円を追加している。
Activityは以前作ったものから変わっていないのでソースは省略する。
実行すると以下のようになる。
※実機で動かしたところでは気にならなかったのだが、キャプチャーすると画像が少し崩れてしまっている
画面をタッチすると次々と円が描かれて行く。
しかし本来なら、こういう用途にはSurfaceViewを使ったほうが良いだろう…。
ピンバック: 【Android】SurfaceViewを使う