【问题标题】:How to save finger drawing view when orientation changes?方向改变时如何保存手指绘图视图?
【发布时间】:2016-04-01 21:50:31
【问题描述】:

假设我有一个托管在主活动中的自定义绘图视图。现在,当设备的方向发生变化时,我正在努力保存绘图状态。我在方向更改后收到NullPointerException。所以我可以毫无问题地画画,但是在我旋转设备后它会崩溃。请给我一个提示,我很沮丧。这是我的绘图视图。在这一行获取 NPE:drawCanvas.drawPath(drawPath, drawPaint);when 调用 performTouchEvent() 后轮换

public class DrawingView 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);
    private ArrayList<MotionEvent> myObject = new ArrayList<MotionEvent>(100);
    //drawing path
    private Path drawPath;
    //drawing and canvas paint
    private Paint drawPaint, canvasPaint;
    //initial color
    private int paintColor = 0xFF660000, paintAlpha = 255;
    //canvas
    private Canvas drawCanvas;

    //canvas bitmap
    private Bitmap canvasBitmap;
    //brush sizes
    private float brushSize, lastBrushSize;
    //erase flag
    private boolean erase=false;

    public DrawingView(Context context, AttributeSet attrs){
        super(context, attrs);
        setupDrawing();
    }

    //setup drawing
    private void setupDrawing(){
        //prepare for drawing and setup paint stroke properties
        brushSize = getResources().getInteger(R.integer.medium_size);
        lastBrushSize = brushSize;
        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setStrokeWidth(brushSize);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);
        canvasPaint = new Paint(Paint.DITHER_FLAG);
    }


    //size assigned to view
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
    }

    //draw the view - will be called after touch event
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
        canvas.drawPath(drawPath, drawPaint);
    }

    //register user touches as drawing action
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        getParent().requestDisallowInterceptTouchEvent(true);
        //respond to down, move and up events
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                performTouchEvent(event);

        }
        //redraw
        invalidate();
        eventList.add(MotionEvent.obtain(event));
        return true;

    }

    private void performTouchEvent(MotionEvent event) {
        float touchX = event.getX();
        float touchY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                drawPath.lineTo(touchX, touchY);
                drawCanvas.drawPath(drawPath, drawPaint);
                drawPath.reset();
                break;
        }
        invalidate();
        eventList.add(MotionEvent.obtain(event));
    }


    //update color
    public void setColor(String newColor){
        invalidate();
        //check whether color value or pattern name
        if(newColor.startsWith("#")){
            paintColor = Color.parseColor(newColor);
            drawPaint.setColor(paintColor);
            drawPaint.setShader(null);
        }
        else{
            //pattern
            int patternID = getResources().getIdentifier(
                    newColor, "drawable", "com.androbro.navigationdrawerproject");
            //decode
            Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
            //create shader
            BitmapShader patternBMPshader = new BitmapShader(patternBMP,
                    Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
            //color and shader
            drawPaint.setColor(0xFFFFFFFF);
            drawPaint.setShader(patternBMPshader);
        }
    }

    //set brush size
    public void setBrushSize(float newSize){
        float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                newSize, getResources().getDisplayMetrics());
        brushSize=pixelAmount;
        drawPaint.setStrokeWidth(brushSize);
    }

    //get and set last brush size
    public void setLastBrushSize(float lastSize){
        lastBrushSize=lastSize;
    }
    public float getLastBrushSize(){
        return lastBrushSize;
    }

    //set erase true or false
    public void setErase(boolean isErase){
        erase=isErase;
        if(erase)  {
            drawPaint.setColor(Color.WHITE);//set the color to white
        }
        else drawPaint.setColor(paintColor); //if erase is set to false, it will use the previous color.
    }

    //start new drawing
    public void startNew(){
        drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        invalidate();
    }

    //return current alpha
    public int getPaintAlpha(){
        return Math.round((float)paintAlpha/255*100);
    }

    //set alpha
    public void setPaintAlpha(int newAlpha){
        paintAlpha=Math.round((float)newAlpha/100*255);
        drawPaint.setColor(paintColor);
        drawPaint.setAlpha(paintAlpha);
    }

    @Override
    public Parcelable onSaveInstanceState()
    {
        Log.i("Saving", "drawing");
        Bundle bundle = new Bundle();
        bundle.putParcelable(EXTRA_STATE, super.onSaveInstanceState());
        bundle.putParcelableArrayList(EXTRA_EVENT_LIST, eventList);

        return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state)
    {
        Log.i("OnRestore", "state");

        if (state instanceof Bundle)
        {
            Bundle bundle = (Bundle) state;
            super.onRestoreInstanceState(bundle.getParcelable(EXTRA_STATE));
            eventList = bundle.getParcelableArrayList(EXTRA_EVENT_LIST);
            if (eventList != null) {
                Log.i("EventList", "is not null");
                myObject = new ArrayList<>(eventList);
            } else{
                return;
            }

            for (MotionEvent event : myObject) {
                Log.i("Event", "" + event);
                performTouchEvent(event);
            }
            return;
        }
        super.onRestoreInstanceState(state);
    }
}

【问题讨论】:

    标签: android


    【解决方案1】:

    随着设备旋转,Activity 和视图都将被销毁,您应该覆盖 onSaveInstanceState(Bundle outState) 方法以将重要数据保存在 Bundle 对象中并再次恢复,请记住此对象应实现 Parcelable Interface,实际上在你的情况下Bitmap 对象是Parcelable 但是如果你通过Bundle 因为屏幕尺寸变化,视图的尺寸会不同,你需要一个不同尺寸的Bitmap要么。

    另一种方法是扩展绘图Path 并实现Parcelable,以便您可以使用Bundle 传递它,并在旋转后重绘Path

    如果您想了解更多关于Parcelable 的信息,请勾选此项:

    How can I make my custom objects Parcelable?

    【讨论】:

    • 谢谢!将寻求扩展 Path,似乎是一个合理的选择。
    • 我的荣幸,祝你好运
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多