Membuat Aplikasi Paint dengan onSaveInstanceState dan onRestore Aplikasi Android

Image result for Aplikasi paint android

1. PAINT

Berikut ini merupakan sebuah  aplikasi  menggambar  yang  di operasikan didalam android. Didalam aplikasi  yang saya buat, saya menggunakan dua class java dan  satu  layout yaitu :
- MyCanvas.java
- MainActivity.java
- activity_main.xml

a. MyCanvas.java

Didalam MyCanvas ini terdapat beberapa variable yang berfungsi untuk mengatur gambar yang akan dibuat. Seperti mBitmap, mCanvas (tempat atau frame untuk menggambar), mPath, mBitmapPaint, dan mDrawPoint. Juga terdapat beberpa method seperti setupPaint()  yang berfungsi untuk mengatur path, warna, dan ukuran gambar yang dibuat, onSizeChanged() mengatur posisi atau letak paint, lalu ada onDraw mengatur tentang canvas dan sebagainya.
Berikut Source kodenya:

public class MyCanvas extends View {
    Context context;
    private Bitmap  mBitmap;
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint   mBitmapPaint;
    private boolean mDrawPoint;

    int stateToSave=1;

    private Paint mPaint;


    public MyCanvas(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        System.out.println("init");
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        setupPaint();
    }

    private void setupPaint()
    {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFF000000);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(4f);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (stateToSave==1) {
            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        }else {
            mBitmap = Bitmap.createScaledBitmap(mBitmap, w, h, true);
        }
        stateToSave++;
        mCanvas = new Canvas(mBitmap);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        System.out.println("on draw");
        canvas.drawColor(0xFFAAAAAA);

        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        mDrawPoint=true;
    }
    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mDrawPoint=false;
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }

    public void clear(){
        mCanvas.drawColor(0, PorterDuff.Mode.CLEAR );
        invalidate();
    }

    private void touch_up() {
        if(mDrawPoint == true) {
            mCanvas.drawPoint(mX, mY, mPaint);
        } else {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw
            mPath.reset();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }

b. MainActivity.java
Didalam MainActivity ini berfungsi untuk mengimplementasikan dari MyCanvas ke activity_main.xml yang didalamnya terdapat fungsi onCreate dan clear (untuk menghapus gambar).
Berikut adalah source codenya :

package com.example.asus.apublic;

import android.support.v7.app.AppCompatActivity;
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);

        myCanvas = (MyCanvas) findViewById(R.id.canvas);
    }
    public void clear (View view){

        myCanvas.clear();
    }
}

c. activity_main.xml

Berisi tentang tampilan dari aplikasi paint yang mana didalamnya terdapat button clear untuk menghapus jika ia di klik maka akan menjalankan method clear() da nada canvas yang akan menjalankan class MyCanvas.java, berikut source codenya:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/inner"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.asus.apublic.MainActivity">

    <com.example.asus.apublic.MyCanvas
        android:id="@+id/canvas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_marginBottom="18dp"
        android:layout_marginEnd="25dp"
        android:drawableTop="@drawable/images"
        android:onClick="clear"
        android:text="Clear" />

</RelativeLayout>

2. onSaveInstance
Kegunaan dari onSave ini adalah agar saat di rotate data tidak hilang, data tersimpan sementara yang nantinya akan dipanggil kembali didalam onRestore. Berikut adalah penggunaan dari onSave dari aplikasi yang saya buat :

@Override
protected Parcelable onSaveInstanceState()
{
    System.out.println("save instance");
    Bundle bundle = new Bundle();
    bundle.putParcelable("instanceState", super.onSaveInstanceState());
    bundle.putParcelable("mBitmap", mBitmap);
    bundle.putInt("stateToSave", stateToSave);
    return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state)
{
        System.out.println("on restore");
        Bundle bundle = (Bundle) state;
        mBitmap = bundle.getParcelable("mBitmap");
        stateToSave = bundle.getInt("asd");
        super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
}

3. AndroidManifest
Agar saat dirotate data dapat disimpan, maka perlu adanya perubahan config didalam manifestnya. Dengan menambahkan  (seperti gambar dibawah) pada Activity nya


Untuk source kodenya :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.asus.apublic">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity" android:configChanges="screenSize|orientation">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4. Design main_activity

Dalam tampilan layout, saya menggunakan gambar “images.png” berupa gambar sampah/clear yang gambarnya berada pada folder  res-drawable.

5. Kode Keseluruhan di MyCanvas.java
package com.example.asus.apublic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by ASUS on 4/14/2018.
 */

public class MyCanvas extends View {
    Context context;
    private Bitmap  mBitmap;
    private Canvas  mCanvas;
    private Path    mPath;
    private Paint   mBitmapPaint;
    private boolean mDrawPoint;

    int stateToSave=1;

    private Paint mPaint;


    public MyCanvas(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        System.out.println("init");
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        setupPaint();
    }

    private void setupPaint()
    {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFF000000);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(4f);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (stateToSave==1) {
            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        }else {
            mBitmap = Bitmap.createScaledBitmap(mBitmap, w, h, true);
        }
        stateToSave++;
        mCanvas = new Canvas(mBitmap);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        System.out.println("on draw");
        canvas.drawColor(0xFFAAAAAA);

        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        mDrawPoint=true;
    }
    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mDrawPoint=false;
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }

    public void clear(){
        mCanvas.drawColor(0, PorterDuff.Mode.CLEAR );
        invalidate();
    }

    private void touch_up() {
        if(mDrawPoint == true) {
            mCanvas.drawPoint(mX, mY, mPaint);
        } else {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw
            mPath.reset();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }
    @Override
    protected Parcelable onSaveInstanceState()
    {
        System.out.println("save instance");
        Bundle bundle = new Bundle();
        bundle.putParcelable("instanceState", super.onSaveInstanceState());
        bundle.putParcelable("mBitmap", mBitmap);
        bundle.putInt("stateToSave", stateToSave);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state)
    {
            System.out.println("on restore");
            Bundle bundle = (Bundle) state;
            mBitmap = bundle.getParcelable("mBitmap");
            stateToSave = bundle.getInt("asd");
            super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
    }
}


Sumber Referensi :
https://stackoverflow.com/questions/19986071/android-how-to-save-custom-finger-paint-view-on-orientation-change


Membuat Aplikasi Paint dengan onSaveInstanceState dan onRestore Aplikasi Android Membuat Aplikasi Paint dengan onSaveInstanceState dan onRestore Aplikasi Android Reviewed by Unknown on 09:26 Rating: 5

No comments