【Androidプログラミング】ペイントアプリ(お絵描きアプリ)の作り方実況解説

Android Studioで簡単なペイント(お絵描き)アプリの作り方について解説します。

■言語:java
■AndroidStudio 4.1.2
■対象:軽くjava入門程度は終わらせたので「何か実際にアプリを作ってみたい」という人

 

動画で解説

 

コード

▼activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <com.example.paintapp.MyCanvas
        android:id="@+id/myCanvas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClear"
        android:text="clear"
        app:layout_constraintBottom_toBottomOf="@+id/myCanvas"
        />


</androidx.constraintlayout.widget.ConstraintLayout>

 

▼MainActivity.java

package com.example.paintapp;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private MyCanvas myCanvas;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //6)描画のid取得
        myCanvas =(MyCanvas)findViewById(R.id.myCanvas);
    }

    //5)クリアメソッド(4)呼び出し
    public void onClear(View view){
        myCanvas.clearCanvas();
    }

}

 

▼MyCanvas.java

package com.example.paintapp;

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

import androidx.annotation.Nullable;

public class MyCanvas extends View {

    private Path path;
    private Paint paint;

    public MyCanvas(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //1)コンストラクタ(≒必需品)
        path = new Path();//線を引いたり、図形を描いたり、要するにグラフィック

        paint = new Paint();//筆の種類
        paint.setColor(Color.RED);//色の指定
        paint.setStyle(Paint.Style.STROKE);//線をひく
        paint.setStrokeWidth(20);//幅

    }

    //2)onDraw(描画の準備/プロペラが回りだした状態)

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path,paint);
    }


    //3)実際の操縦 (条件分岐:押したとき、動かしたとき、放した時)

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //(3-1)座標を取得(x座標、y座標)
        float x = event.getX();
        float y = event.getY();

        //(3-2)タッチの処理
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x,y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(x,y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        //return super.onTouchEvent(event);
        return true;
    }


    //4)クリア処理
    public void clearCanvas(){
        path.reset();
        invalidate();
    }

}

 

テキスト解説

AndroidStudioで、簡単なペイントアプリを作るやり方について解説していきます。
完成見本がこちらです。

画面になぞったところが描画できて、お絵描きが出来る、というアプリです。
消したら戻る、という非常にシンプルな作りになっています。

今は青色ですが
ここをレッドに変えてあげて
太さも20に変えてあげると

太い赤字で描けるようになっています。

こんな感じですね。
絵のクオリティはさておき
なぞったところに線がひけて、離すと、線はひけない。
結果としてイラストがかけるということですね、

クリアボタンで消すことができると、いうことですね。
それでは早速作業にいきましょう。
といきたいところなんですけども、簡単な流れについて
ざっくり解説したいと思います。

*****************************
【主な作業の流れ】
実際の作業の前に、作業の流れについてざっと説明しておきます。


まずプロジェクトを起動すると、xmlとjava、2つのファイルが出来ますよね。
ここはOKですよね。
今回は、それに加えて、もう1つjavaのクラスを作ります。
ということで、まず、今回は3つのファイルを扱っていく、というのが大きなテーマになります。


で、こいつが何なんだって話を少しだけしますね。
結論から言うとこいつはViewを継承したクラス、ということになります。

まずViewとは何ぞやと、いうところから簡単に説明します。

Viewっていうのは聞いたことありますかね。
TextViewとか、ImageViewとか、あとButtonなんかもViewグループに属しています。

継承というのは「親子関係」だと思ってください。
今回はonDrawっていうViewクラスのメソッドを使うので
Viewを継承したクラスを作る、ということですね。

onDraw。ま、字面でわかるとおり、絵を描く時に使うメソッドです。

親子関係について、もうちょっとだけ説明しておきますね。
なんでこんなことするんやと。

———– ———

ちょっと話が飛びまして、自動車を例にとります。
自動車といっても、色々あるんですよね。
これら1個1個がアプリだと思ってください。
乗用車、救急車、消防車、トラック。
同じようなアプリで ちょっとずつ違うと。

でも共通している部分があるやろと。
ここでいうと、アクセルとかブレーキとかエンジンとか。

プログラミングでは、様々なアプリを作るときに、
共通する部分は、上位でいったんまとめておいて、
特別な機能だけ用意する、ということをよくします。

これの上にあたるものが親クラス。もしくはスーパークラス
で、それを継承する子供は、を子クラス、もしくはサブクラスといったりしますので
用語として覚えておいてください。
子供は、これらの親の遺伝子をそのまま引き継ぐことが出来るので便利ですよねって話です。
で、今回も「onDraw」っていうViewグループのメソッドを使うので、
view、このお父さんお母さんの遺伝子は引き継いだまま
新しい機能を追加しよう、というのが継承になります。

まあ、長々しゃべりましたけど、 大事なのはここだけ。


要するに、もう1個javaを作りますよ、と。
それはViewという親を持つ、サブクラスですよと、いうことですね。

こまかい理屈はともかく
こんな感じでふんわりと作業イメージが理解できたところで、始めて行きましょう。

******************************************************
******************************************************
【プロジェクトの起動】

プロジェクトを起動します。
まずはプロジェクトを起動します。
名前は適当に
PaintApp、とかにします。

これでお決まりのレイアウトと、メインjavaが出来ました。
レイアウトとかは最後にちょこっとやるだけなので、
さっそくサブクラスを作っていきましょう。

***************************
【サブクラス】

次に、この図でいう、これ、サブクラスを作っていきます。
今回のメインとなる部分です。

MainActivity.javaと同列にしたいので、その1つ上、パッケージを右クリック
⇒new ⇒java class
名前を適当にMyCanvasとかにしましょう。

そうすると、MainActivityと同列にMyCanvasができました。

で、これがviewを継承してますよっつー、定型文があるんで、
解説は後にするので、まず正解だけ書いていきますね。

このMyCanvas(子)のあとに、extends View (親)と追記

これでViewを継承した子供が「MyCanvas」という意味になります。
親をViewにもつ、サブクラス「MyCanvas」ができました。

それから赤字が出てるので、一番上のクリエイトコンストラクタをクリック。

ここで「コンストラクタの生成」という作業をします。

説明は後にして、ひとまず正解だけやっていきますね。
この辺はもう、お決まりの流れなので、流れにそってやっていけばOKです。

4つ用意されてるので、どれかを選びます。
普通は上から順に選ぶのですが、今回は上から2つ目

public MyCanvas(Context context, AttributeSet attrs) {
super(context, attrs);
を選びます、

これを選ばないとですね、一番上のやつだと、この画面をxmlに重ねることができないんですよね。
逆に、これを(context context)を使いたい場合は、
今レイアウトの指定をMyCanvasの方に書き換えて(飛ばして)あげるとOKです。(※ただし今回はしない)

ただし今回は、xmlに重ねたいので、2つ目の方を使って行きます。

————————————
「コンストラクタ」っていう新しい用語が出てきてわかりにくいと思うんですが
教科書的な説明をすると
「クラスを新しく作った時に実行されるもの」になります。
で、この言い方だとわかりにくいので
大雑把に説明すると「必需品」だと思ってください。

クラスを新しく作ったときに実行されるということは、
このクラスには無くてはならないもの、と言い換えられますよね。

例えば、実際の画像編集ソフトでいうと、


このツールバーとかになるんですかね。
ここは、画像を描こうが、かくまいが、クラスを実行したときにかならず実行されて生成されるプログラム。
で、別にカンバスを用意して、絵を描いていく、というのが手順ですけどもそれと同じです。

筆はどうすんの?
色はどうすんの?
太さはどうすんの?

作業の前に、、最低限用意しておかなければいけない「必需品」があります。
それをこの中にまとめて最初に書いておきましょうっていうのがコンストラクタ、みたいな覚え方でOKだと思います。

————————————
なんとなくわかりましたかね。
作業の流れとしては

//1)必需品
とりあえず必需品を用意したら

//2)onDraw(描画の準備/プロペラが回りだした状態)
描画の命令onDrawをかいて

 

//3)実際の操縦 (条件分岐:押したとき、動かしたとき、放した時)
それを押したときに描くのか、
放したときはどうするのか、
おしたままムーブしたらどうするのか、みたいなのを書いていきます。

そして最後に
//4)クリア処理

ざっくり言うとこの流れです。
では必需品からやっていきましょう。

 

1.コンストラクタ(必需品)

それではまず、必需品を用意していきましょう。

ここは口で説明するより見てもらった方がわかりやすいと思います。

————–
▼まずパスを用意(線を引いたりグラフィック系につかう)
path = new Path();//線を引いたり、図形を描いたり、要するにグラフィック
インポートでandroidグラフィック
private Path path;
を定義。

————–
▼次にペイントで、筆のスタイルを決めていきます
paint = new Paint();//筆の種類

フィールドに宣言
private Paint paint;

では、paintで筆を色々定義していきましょう。
————–

paint.setColor(Color.BLUE);//色の指定
paint.setStyle(Paint.Style.STROKE); //線をひく
paint.setStrokeWidth(10);//幅

pathとpaint。
筆を選んで(paint)
線を引く(path)みたいな感じですかね。
さて。これで必需品が出来たので
描画の命令「onDraw」を書いていきましょう。

2)onDraw

それでは次に
//2)onDraw(描画の命令)
のところを入れていきましょう。
「onD」と入れると、もう出てくるので、それをクリック。

canvas.drawPath(path,paint);

ここはこれで終了です。
具体的な処理を次に書いていきます。

//3)タッチしたときの処理(押したとき、動かしたとき、離した時)

さて、描画の命令もできたので
タッチしたときのイベントを書いていきます。
onT と入れたら出てきますね。

この中に色々書いていきます。
まずは
//(3-1)座標を取得(x座標、y座標)
をして、次に
//(3-2)タッチの処理
を書いていきます。

まずはタッチしたときの座標の取得。
float x = event.getX();
float y = event.getY();

floatはintとかの仲間ですが、intは整数、floatは浮動小数点を扱うときに使用します。

それでは、タッチの処理を書いていきましょう。

タッチには3種類あるので、知らない方はここで覚えてください。

①タッチした瞬間(ACTION_DOWN
②動かしている間(ACTION_MOVE
③手を離す(ACTION_UP

 

——————

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //(3-1)座標を取得(x座標、y座標)
        float x = event.getX();
        float y = event.getY();

        //(3-2)タッチの処理
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x,y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(x,y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        //return super.onTouchEvent(event);
        return true;
    }

invalidate();っていうのはですね
マウスを動かしている間、xy座標を更新し続ける必要があるので記述します。
ダウンの方はなくても動くんですが、連動しているので慣例的に描くのが慣例のようです。

で、最後の
return super.onTouchEvent(event);
ですけど、これは消して、
return true;
にしてください。

trueを返すと、「作業が完了しました」という意味になります
一方、こっち(return super.onTouchEvent(event);)はですね、falseを返すので、作業が完了していないことになってエラーになります。

さあ、もうこれでほぼ出来ました。
最後クリア処理を書いたら、もうほぼ完成です。

4)クリア処理

クリア処理は簡単です。
リセットすればOKです。

//4)クリア処理
public void clearCanvas(){
path.reset();
invalidate();
}

プログラミングはこれでOKなので
これをレイアウトに載せてあげましょう。
constraintlayoutで進めてめていきます。

———————————
出てこない場合は、一回エミュレータを起動してあげると

———————————

xmlにいってパレットから、サブクラス名を指定すると出てきますので
いつもviewを追加するようにズルズルっと持っていってください。
これで入りました。

<com.example.paintapp.MyCanvas
android:id=”@+id/myCanvas”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_weight=”1″ />

出てこない場合は、パッケージ名+クラス名で指定できます。
幅と高さもマッチペアレント。

それから最後にボタンを追加しておきましょう。

ボタンtextは適当に「clear」とかにして。
idはどうでもいいんですけど、
クリックするので、オンクリック処理が必要ですね、
わかりやすくonClear。

<Button
android:id=”@+id/button”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:onClick=”onClear”
android:text=”clear”
app:layout_constraintBottom_toBottomOf=”@+id/myCanvas” />

 

5)仕上げ

//5)クリアメソッド(4)呼び出し
public void onClear(View view){
myCanvas.clearCanvas();
}

myCanvasがないので、
上で変数を用意してあげます。
private MyCanvas myCanvas;

これでOKかと思いきや、
レイアウトの描画のidを取得してなかったですね。
//6)描画のid取得
myCanvas =(MyCanvas)findViewById(R.id.myCanvas);

***************************
【完成】

 

非常に簡単ではありますが
ペイントアプリの作り方解説でした。

慣れてきたら、いろんな機能を追加してオリジナルにカスタマイズしてみてください。