●viewにbitmapを表示してグラフィックス


画面サイズに合わせて表示サイズが変わったりしません。
小さいbitmapなら小さいまま、大きいビットマップなら画面からはみ出て見えなくなります。

サイズが自動で変わって欲しいならandroid.widget.ImageViewをどうぞ。
    ImageView.setImageBitmap(bitmap);
    ImageViewだと、ビットマップをこのように指定するとあとは勝手に描画してくれます。
    だからonDrawは何も書かなくてもいいです。
    あとは、あまり変わらないですけどね。

■まずは基本的なコードから、

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    uview uv;
    android.graphics.Bitmap bitmap;
    android.graphics.Canvas canvas;
    android.graphics.Paint paint;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uv=new uview(this) ;
        setContentView(uv);
        bitmap = android.graphics.Bitmap.createBitmap(500, 500, android.graphics.Bitmap.Config.RGB_565);
        canvas = new android.graphics.Canvas(bitmap);
        canvas.drawColor(android.graphics.Color.BLUE);
        paint = new android.graphics.Paint();
        paint.setStyle(android.graphics.Paint.Style.FILL);
        paint.setColor(android.graphics.Color.WHITE);
        canvas.drawLine(0, 0, 500, 500, paint);
    }
    private class uview extends android.view.View {
        public void onDraw(android.graphics.Canvas c){
            c.drawBitmap(bitmap, 0, 0, paint);
        }
    }
}

実際に動かしてみると、このようになります。



まず、ビットマップを作成しています。
bitmap = android.graphics.Bitmap.createBitmap(500, 500, android.graphics.Bitmap.Config.RGB_565);
ここでおや?と思うのがRGB_565の所、これはピクセルフォーマットと言って、ARGB4444やARGB8888とかありますが
ピクセルの色の表現形式です。
色の情報が多かったり、透過効果が追加されたりしますが、今は、一番メモリ使用量がすくないRGB_565に
しておきます。

次にCanvasをnewしています。
Canvasとは線を描いたり文字を書いたりする道具です。
canvas = new android.graphics.Canvas(bitmap);

で、いきなりビットマップをブルーに塗りつぶします。
canvas.drawColor(android.graphics.Color.BLUE);

次に描画するペンやブラシみたいな役割をするPaintを生成して設定します。
paint = new android.graphics.Paint();
paint.setStyle(android.graphics.Paint.Style.FILL);
paint.setColor(android.graphics.Color.WHITE);

その後に設定したPaintを使ってCanvasで線を引きます
canvas.drawLine(0, 0, 500, 500, paint);

これで、線の引かれたビットマップは作成されましたが、画面に表示されません。
表示するために
public void onDraw(android.graphics.Canvas c){
    c.drawBitmap(bitmap, 0, 0, paint);
}
onDrawで座標0,0から表示します。
再描画をしたいときは、どこかでthis.invalidate();を呼ぶと、
システムが暇になったときに再描画してくれます。
どうしても強制的に再描画したいなら、onDrawの中でするしかありません。



■画面いっぱいにbitmapを表示する


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    uview uv;
    android.graphics.Bitmap bitmap;
    android.graphics.Canvas canvas;
    android.graphics.Paint paint;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uv=new uview(this) ;
        setContentView(uv);

        uv.post(new Runnable() {
            public void run() {
                bitmap = android.graphics.Bitmap.createBitmap(uv.getWidth(), uv.getHeight(), android.graphics.Bitmap.Config.RGB_565);
                canvas = new android.graphics.Canvas(bitmap);
                canvas.drawColor(android.graphics.Color.BLUE);
                paint = new android.graphics.Paint();
                paint.setStyle(android.graphics.Paint.Style.FILL);
                paint.setColor(android.graphics.Color.WHITE);
                canvas.drawLine(0,0,uv.getWidth(),uv.getHeight(), paint);
                uv.invalidate();
            }
        });

    }
    private class uview extends android.view.View {
        public uview(android.content.Context c){
            super(c);
        }
        public void onDraw(android.graphics.Canvas c){
            c.drawBitmap(bitmap, 0, 0, paint);
        }
    }
}

実際に動かしてみると、このようになります。



viewが画面に表示される前に縦横のサイズを呼び出そうとするとアプリが落ちます。
そこで、処理をviewにスケジューリングします。
それにより、処理が最後に行われるようになり、適切な縦横サイズが取得できます。



■お絵かきできるようにする


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    uview uv;
    static android.graphics.Bitmap bitmap;
    static android.graphics.Canvas canvas;
    static android.graphics.Paint paint;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uv=new uview(this);
        uv.post(new Runnable() {
            public void run() {
                //if(bitmap==null) {
                    bitmap = android.graphics.Bitmap.createBitmap(uv.getWidth(), uv.getHeight(), android.graphics.Bitmap.Config.RGB_565);
                    canvas = new android.graphics.Canvas(bitmap);
                    canvas.drawColor(android.graphics.Color.WHITE);
                    paint = new android.graphics.Paint();
                    paint.setStyle(android.graphics.Paint.Style.FILL);
                    paint.setColor(android.graphics.Color.BLACK);
                    paint.setStrokeWidth(20);
                    paint.setAntiAlias(true);
                //}
                uv.invalidate();
            }
        });
        uv.setOnTouchListener(new OnTouch_listener());
        setContentView(uv);
    }
    private class uview extends android.view.View {
        public uview(android.content.Context c){
            super(c);
        }
        public void onDraw(android.graphics.Canvas c){
            c.drawBitmap(bitmap, 0, 0, paint);
        }
    }
    private class OnTouch_listener implements android.view.View.OnTouchListener {
        float old_x,old_y;
        @Override
        public boolean onTouch(android.view.View v, android.view.MotionEvent e) {
            float x = e.getX();
            float y = e.getY();
            if(android.view.MotionEvent.ACTION_DOWN!=e.getAction()) {
                canvas.drawLine(old_x, old_y, x, y, paint);
                canvas.drawCircle(x,y,10,paint);
                canvas.drawCircle(old_x,old_y,10,paint);
                v.invalidate();
            }
            old_x = x;
            old_y = y;
            return true;
        }
    }
}

実際に動かして絵を書いてみると、このようになります。



viewのイベントで座標を取得してビットマップに描画しています。
viewの座標とビットマップの座標がだいたい一致していることがわかります。
線の前後に円を描くことによって線と線の接合部分に白い境界が出来るのを防いでいます。



■ある座標の色を取得する


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    uview uv;
    static android.graphics.Bitmap bitmap;
    static android.graphics.Canvas canvas;
    static android.graphics.Paint paint;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uv=new uview(this);
        uv.post(new Runnable() {
            public void run() {
                //if(bitmap==null) {
                    bitmap = android.graphics.Bitmap.createBitmap(uv.getWidth(), uv.getHeight(), android.graphics.Bitmap.Config.RGB_565);
                    canvas = new android.graphics.Canvas(bitmap);
                    canvas.drawColor(android.graphics.Color.WHITE);
                    paint = new android.graphics.Paint();
                    paint.setStyle(android.graphics.Paint.Style.FILL);
                    paint.setColor(android.graphics.Color.BLACK);
                    paint.setStrokeWidth(20);
                    paint.setAntiAlias(true);
                    canvas.drawLine(0,0,uv.getWidth(),uv.getHeight(), paint);
                    canvas.drawLine(uv.getWidth(),0,0,uv.getHeight(), paint);
                //}
                uv.invalidate();
            }
        });
        uv.setOnTouchListener(new OnTouch_listener());
        setContentView(uv);
    }
    private class uview extends android.view.View {
        public uview(android.content.Context c){
            super(c);
        }
        public void onDraw(android.graphics.Canvas c){
            c.drawBitmap(bitmap, 0, 0, paint);
        }
    }
    private class OnTouch_listener implements android.view.View.OnTouchListener {
        android.os.Vibrator vi;
        android.media.ToneGenerator tg;
        public OnTouch_listener() {
            super();
            vi=(android.os.Vibrator)getSystemService(VIBRATOR_SERVICE);
            tg = new android.media.ToneGenerator(android.media.AudioManager.STREAM_SYSTEM, android.media.ToneGenerator.MAX_VOLUME);
        }
        @Override
        public boolean onTouch(android.view.View v, android.view.MotionEvent e) {
            int flag=0;
            if(android.view.MotionEvent.ACTION_UP!=e.getAction()) {
                int count=e.getPointerCount();
                for(int i=0;i<count;i++) {
                    try {
                        if (android.graphics.Color.BLACK == bitmap.getPixel((int) e.getX(i), (int) e.getY(i))) {
                            flag = 1;
                        }
                    }catch(Exception ex){}
                }
            }
            if(1==flag){
                start();
            }else {
                end();
            }
            return true;
        }
        int _flag=0;
        private void start(){
            if(1!=_flag) {
                _flag = 1;
                vi.vibrate(5000);
                tg.startTone(android.media.ToneGenerator.TONE_DTMF_9, 5000);
            }
        }
        private void end(){
            _flag=0;
            vi.cancel();
            tg.stopTone();
        }
    }
}

実際に動かしてみると、このようになります。



bitmapに描画された×印の上の黒い部分に指を滑らせると音とバイブレーションが発生します。
詳しいバイブレーションの動きはこちらへ

android.graphics.Color.BLACK == bitmap.getPixel((int) e.getX(), (int) e.getY())

の条件式により現在の座標の色を取得して判断しています。
ただ、bitmapの座標より大きな値を入れて呼び出すと例外が発生しますので try{}catch で囲んであります。



▲トップページ > android