Solution to Challenge: Saving State and Rotating Box


#1

I took some idea from previous posts and selected the code that’s shorter and easier to read.

Box.java

import android.graphics.PointF;

public class Box {
    private PointF mOrigin;
    private PointF mCurrent;
    private PointF mPointerOrigin;
    private float  angle;

    public Box(PointF origin){
        mOrigin = origin;
        mCurrent = origin;
    }

    public PointF getPointerOrigin() {
        return mPointerOrigin;
    }

    public void setPointerOrigin(PointF pointerOrigin) {
        mPointerOrigin = pointerOrigin;
    }

    public float getAngle() {
        return angle;
    }

    public void setAngle(float angle) {
        this.angle = angle;
    }


    public PointF getCurrent(){
        return mCurrent;
    }

    public void setCurrent(PointF current){
        mCurrent=current;
    }

    public PointF getOrigin() {
        return mOrigin;
    }
}

BoxDrawingView.Java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes;


public class BoxDrawingView extends View {
    private static final String TAG = "BoxDrawingView";
    private Box mCurrentBox;
    private List<Box> mBoxen = new ArrayList<>();
    private Paint mBoxPaint;
    private Paint mBackgroundPaint;

    public BoxDrawingView(Context context) {
        this(context,null);
    }

    public BoxDrawingView(Context context, AttributeSet attrs){
        super(context, attrs);

        mBoxPaint = new Paint();
        mBoxPaint.setColor(0x22ff0000);

        mBackgroundPaint = new Paint();
        mBackgroundPaint.setColor(0xfff8efe0);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        PointF touchPoint  = null;
        PointF touchPoint2 = null;
        for (int i=0;i<event.getPointerCount();i++) {
            if(event.getPointerId(i)==0)
                touchPoint = new PointF(event.getX(i), event.getY(i));
            if(event.getPointerId(i)==1)
                touchPoint2 = new PointF(event.getX(i), event.getY(i));
        }


        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mCurrentBox = new Box(touchPoint);
                mBoxen.add(mCurrentBox);
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mCurrentBox.setPointerOrigin(touchPoint2);
                break;
            case MotionEvent.ACTION_MOVE:
                if(touchPoint  != null )
                mCurrentBox.setCurrent(touchPoint);
                if(touchPoint2 != null ) {
                    PointF boxOrigin     = mCurrentBox.getOrigin();
                    PointF pointerOrigin = mCurrentBox.getPointerOrigin();
                    float angle2 = (float) Math.atan2(touchPoint2.y   - boxOrigin.y, touchPoint2.x   - boxOrigin.x);
                    float angle1 = (float) Math.atan2(pointerOrigin.y - boxOrigin.y, pointerOrigin.x - boxOrigin.x);
                    float calculatedAngle = (float) Math.toDegrees(angle2 - angle1);
                    if (calculatedAngle < 0) calculatedAngle += 360;
                    mCurrentBox.setAngle(calculatedAngle);
                    Log.d(TAG, "Set Box Angle " + calculatedAngle);
                }
                invalidate();
            break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG, "Finger UP Box Set");
                mCurrentBox = null;
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.d(TAG, "Action Cancel Box Set");
                mCurrentBox = null;
                break;
        }

        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawPaint(mBackgroundPaint);

        for(Box box:mBoxen){
            float left   = Math.min(box.getOrigin().x,box.getCurrent().x);
            float right  = Math.max(box.getOrigin().x,box.getCurrent().x);
            float top    = Math.min(box.getOrigin().y,box.getCurrent().y);
            float bottom = Math.max(box.getOrigin().y,box.getCurrent().y);

            float angle = box.getAngle();
            float px = (box.getOrigin().x+box.getCurrent().x)/2;
            float py = (box.getOrigin().y+box.getCurrent().y)/2;
            canvas.save();
            canvas.rotate(angle, px, py);
            canvas.drawRect(left, top, right, bottom, mBoxPaint);
            canvas.restore();
        }
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Log.d(TAG,"Saving Instance State");
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.mBoxList = mBoxen;

        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {

        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        Log.d(TAG,"Restoring Instance State");
        mBoxen = ss.mBoxList;
    }

    private static class SavedState extends BaseSavedState {
        private List<Box> mBoxList ;

        public SavedState(Parcelable superState) {
            super(superState);
            Log.d(TAG,"Saving parcelable");
        }
    }
}

fragment_drag_and_draw.xml

<com.shaodw_wxh.www.draganddraw.BoxDrawingView
    xmlns:android = "http://schemas.android.com/apk/res/android"
    android:id="@+id/box_drawing_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>