문제

I'm trying to create a custom view where a user can draw their signature. One where you can put it into the view programmatically and set the size, etc. I haven't had to do this before so I based it off the fingerpaint class from android api demos. Problem right now is that it erases the object on orientation change and I'm not sure how to get it to not do that.

The code for PaintView

private Bitmap  mBitmap;
private Canvas  mCanvas;
private Path    mPath;
private Paint   mBitmapPaint;
private boolean mDrawPoint;

private int stateToSave;

private Paint mPaint;


public PaintView(Context context) {
    super(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(4);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    System.out.println("w "+w+" h "+h+" oldw "+oldw+" oldh "+oldh);
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
}

@Override
protected void onDraw(Canvas 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;
    }
}
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) {
    getParent().requestDisallowInterceptTouchEvent(true);
    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;
}

As a mini test I added in

@Override
public Parcelable onSaveInstanceState() 
{
    System.out.println("save instance");
    stateToSave++;
    Bundle bundle = new Bundle();
    bundle.putParcelable("instanceState", super.onSaveInstanceState());  
    bundle.putInt("stateToSave", this.stateToSave);

    return bundle;
}

@Override
public void onRestoreInstanceState(Parcelable state) 
{
    System.out.println("on restore");
    if (state instanceof Bundle) 
    {
        System.out.println("on restore");
        Bundle bundle = (Bundle) state;
        this.stateToSave = bundle.getInt("stateToSave");
        super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
        System.out.println(stateToSave);
        return;
    }
    super.onRestoreInstanceState(state);
}

But onRestoreInstance() and onSaveInstance() never get called on orientation change. Here is my code in the oncreate in the activity that makes a paintview.

RelativeLayout inner= (RelativeLayout) findViewById(R.id.inner);

    int width=600;
    int height=360;
    float X= 100;
    float Y=60;

    LayoutParams wrapped = new LayoutParams(width,height);

    PaintView painting=new PaintView(this);

    painting.setX(X);
    painting.setY(Y);
    painting.setLayoutParams(wrapped);
    inner.addView(painting);

Edit: I figured it out why saveinstancestate wasn't calling, I had to give the View an ID and then it would work.

painting.setId(4);

Now I need to figure out how to make it save the drawing.

도움이 되었습니까?

해결책

You need to make sure your View is saveEnabled, try:

setSaveEnabled(true);

You could do this from the constructor of your PaintView.

Also, you may need to make sure that your activities are being destroyed/recreated on orientation change. Make sure you DO NOT have:

<activity name="?"
android:configChanges="keyboardHidden|orientation"
/>

declared for the activity using this View or else the activity won't be destroyed on orientation change. Also, if you have overridden onSaveInstanceState/*onRestoreInstanceState* in those activities you need to call the respective superclass method, either super.onSaveInstanceState() or super.onRestoreInstanceState())

As far as how to actually recreate or save the image for orientation changes how about you save each event that is done in some kind of parcelable List. Save that list in onSaveInstanceState and restore it in onRestoreInstanceState. THen take the list of events and loop through it, calling the respective draw functions. You may need to do some translation of X,Y values based on the new orientation.

The code would look something like this:

public class PaintView extends View {

    private static final String EXTRA_EVENT_LIST = "event_list";
private static final String EXTRA_STATE = "instance_state";
private ArrayList<MotionEvent> eventList = new ArrayList<MotionEvent>(100);

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        getParent().requestDisallowInterceptTouchEvent(true);           
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
            performTouchEvent(event);                
        }             
        return true;
    }

    private void performTouchEvent(MotionEvent event) {
        float x = event.getX();
            float y = event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                break;
                }
                invalidate();
                eventList.add(MotionEvent.obtain(event));           
        }
    }


    @Override
    public Parcelable onSaveInstanceState() 
    {
        System.out.println("save instance");
        Bundle bundle = new Bundle();
        bundle.putParcelable(EXTRA_STATE, super.onSaveInstanceState());  
        bundle.putParcelableArrayList(EXTRA_EVENT_LIST, eventList);

    return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) 
    {
        if (state instanceof Bundle) 
        {
            Bundle bundle = (Bundle) state;
            super.onRestoreInstanceState(bundle.getParcelable(EXTRA_STATE));
            eventList = bundle.getParcelableArrayList(EXTRA_EVENT_LIST);
            if (eventList == null) {
               eventList = new ArrayList<MotionEvent>(100); 
            }
            for (MotionEvent event : eventList) {
               performTouchEvent(event);
            }               
            return;
        }
        super.onRestoreInstanceState(state);
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top