お絵かきアプリを作りたい。描画編

お絵かきアプリを作成してみたいと思います。

参考:https://gist.github.com/547660

前回作成したViewをイベントによって、再描画をする。を元に作成をしてみたいと思います。

お絵かき

まず、前回の丸を描く際に利用した方法を用います。

今回は線を描く方法を考えたいと思います。

線を描く時にドロイド君を書いた時のdrawLineを用いましたが、連続した線を描く為には、drawPathを用います。

drawPathはpathで作成した点をなぞる形で、線を描いてくれます。

またペイントの設定は下記にしました。

paint.setAntiAlias(true);
paint.setColor(Color.LTGRAY);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(6);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);

アンチエイリアス、色をライトグレー、図形を線のみ、線の太さを6、端点を丸く、つなぎ目を丸く

今回利用はしてないのですが、下記のような要素も指定できるようです。

破線(参照:)

タッチのイベントでは、ここで作成をする線のPathを作成します。

public boolean onTouchEvent(MotionEvent e){
 posx = e.getX();
 posy = e.getY();
 switch(e.getAction()){
 case MotionEvent.ACTION_DOWN: //最初のポイント
 path = new Path();
 path.moveTo(posx , posy );
 break;
 case MotionEvent.ACTION_MOVE: //途中のポイント
 path.lineTo(posx, posy);
 invalidate();
 break;
 case MotionEvent.ACTION_UP: //最後のポイント
 path.lineTo(posx, posy);
 invalidate();
 break;
 default:
 break;
 }
 return true;
 }

以上で、タッチをしたところから、なぞる線を描くことができました。動かす度に更新で、再描画されます。

再描画は以下のファンクションで実行します。

//public
@Override
protected void onDraw(Canvas canvas){
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.LTGRAY);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(6);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
if(path != null){
canvas.drawPath(path, paint);
}
}

線を描けたのですが、この線に関して次の線を描いた時に消えてしまいます。

 

次線が記載された時に前の線を残す方法があります。

1、pathを配列で保持しておく。

2、canvasのキャプチャをとって、次の線が描かれたらキャプチャと線を重ねる。

です。今回は2の方法で作成をします。

 

キャプチャを取る方法ですが、通常viewはキャッシュが効かないようになっていますが、キャッシュをONにします。

setDrawingCacheEnabled(true);

ここで作成したキャッシュをビットマップに変換をします。

bitmap = Bitmap.createBitmap(getDrawingCache());

キャッシュを利用していると負荷がかかるので、キャッシュを切ります。

setDrawingCacheEnabled(false);

以上で現状のキャプチャが取れます。これを指を離した瞬間に取得します。

public boolean onTouchEvent(MotionEvent e){
 posx = e.getX();
 posy = e.getY();
 switch(e.getAction()){
 case MotionEvent.ACTION_DOWN: //最初のポイント
 path = new Path();
 path.moveTo(posx , posy );
 break;
 case MotionEvent.ACTION_MOVE: //途中のポイント
 path.lineTo(posx, posy);
 invalidate();
 break;
 case MotionEvent.ACTION_UP: //最後のポイント
 path.lineTo(posx, posy);
 setDrawingCacheEnabled(true);
 bitmap = Bitmap.createBitmap(getDrawingCache());
 setDrawingCacheEnabled(false);
 invalidate();
 break;
 default:
 break;
 }
 return true;
 }

これで描かれた線、及びその背景をbitmapの中にいれる事ができました。

onDrawでこのキャッシュを描画するファンクションを足してみます。

//public
 protected void onDraw(Canvas canvas){
 super.onDraw(canvas);
 if(bitmap != null){
 canvas.drawBitmap(bitmap, 0, 0, null);
 }
 Paint paint = new Paint();
 paint.setAntiAlias(true);
 paint.setColor(Color.LTGRAY);
 paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(6);
 paint.setStrokeCap(Paint.Cap.ROUND);
 paint.setStrokeJoin(Paint.Join.ROUND);

 if(path != null){
 canvas.drawPath(path, paint);
 }
 }

足しました。これで完成です。

 

しかし、これだと、少し、動きが硬い部分が出てしまいます。

フレームレートの問題もあるかと思いますが、ペンの動きを指の動きに追う動きにしたいと思います。

仕組みとしては、前回線の位置と指の位置の間に線を移動させます。そうする事で、ガタガタしてしまう点も滑らかな曲線になってくれます。

case MotionEvent.ACTION_MOVE: //途中のポイント
 posx += (e.getX()-posx)/1.4;
 posy += (e.getY()-posy)/1.4;
 path.lineTo(posx, posy);
 invalidate();
 break;

下記にソースを置いておきます。

package in.andante.touchtest;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;

//描画を行うView
public class TouchCircle extends View{

 private float posx = 0f; //イベントが起きたX座標
 private float posy = 0f; //イベントが起きたY座標
 private Path path = null; //パス
 private Bitmap bitmap = null; //Viewの状態を保存するためのBitmap

 public TouchCircle(Context context){
 super(context);
 }

 public boolean onTouchEvent(MotionEvent e){
 //イベントのタイプごとに処理を設定
 switch(e.getAction()){
 case MotionEvent.ACTION_DOWN: //最初のポイント
 path = new Path();
 posx = e.getX();
 posy = e.getY();
 path.moveTo(e.getX(), e.getY());
 break;
 case MotionEvent.ACTION_MOVE: //途中のポイント
 posx += (e.getX()-posx)/1.4;
 posy += (e.getY()-posy)/1.4;
 path.lineTo(posx, posy);
 invalidate();
 break;
 case MotionEvent.ACTION_UP: //最後のポイント
 path.lineTo(e.getX(), e.getY());
 //キャッシュの中からキャプチャを作成するので、その一瞬の為にキャッシュをON
 setDrawingCacheEnabled(true);
 bitmap = Bitmap.createBitmap(getDrawingCache());
 setDrawingCacheEnabled(false);
 invalidate();
 break;
 default:
 break;
 }
 return true;
 }

 @Override
 protected void onDraw(Canvas canvas){
 super.onDraw(canvas);
 if(bitmap != null){
 canvas.drawBitmap(bitmap, 0, 0, null);
 }
 Paint paint = new Paint();
 paint.setAntiAlias(true);
 paint.setColor(Color.LTGRAY);
 paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(6);
 paint.setStrokeCap(Paint.Cap.ROUND);
 paint.setStrokeJoin(Paint.Join.ROUND);
 if(path != null){
 canvas.drawPath(path, paint);
 }
 }
}

です。

また、背景を白くメニューバーなどを隠すテーマを適用します。

manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="in.andante.touchtest"
 android:versionCode="1"
 android:versionName="1.0">
 <uses-sdk android:minSdkVersion="7" />

 <application android:icon="@drawable/icon" android:label="@string/app_name">
 <activity android:name=".TouchTest"
 android:label="@string/app_name"
 android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 </application>
</manifest>

以上で簡単なお絵かきアプリを制作できました。

  • written on 2011.04.14
  • category : 描画

前後の記事

前の記事:

次の記事:

関連の記事

コメントの投稿

  • サイト内検索

新作アプリの紹介

関連サイトの紹介

アンドロイドアプリ開発TIPS
きぐるみカメラ
ふらいぱん
アンドロイドのデザイン集
Page top↑