【问题标题】:Android: Why can't I paint on my canvas bitmap after rotating screen?Android:旋转屏幕后为什么不能在画布位图上绘画?
【发布时间】:2017-06-12 13:42:26
【问题描述】:

我正在使用 Android 的 Fingerpaint 演示 [1] 来试验 Canvas 和 Bitmaps。我想在屏幕上绘制一个对象,并在屏幕旋转后继续绘制该对象。 Fingerpaint 演示会在屏幕旋转后擦除屏幕 - 我想保留屏幕内容并随屏幕一起旋转。

使用我的代码,我可以旋转屏幕和我绘制的图像。但我不再能够向位图添加任何额外的路径标记。它变得像一个只读位图。有谁知道我做错了什么?

这是我保存图像并在旋转后恢复它的代码。请注意,我将它作为 PNG 保存在一个字节数组中(在 onSaveInstanceState() 中),然后在 onCreate() 中从该字节数组创建一个新的位图(我认为这可以吗?):

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    Log.d("TAG", "Saving state...");
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    canvasView.mBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    imageByteArray = stream.toByteArray();
    savedInstanceState.putSerializable("ByteArray", imageByteArray);
    super.onSaveInstanceState(savedInstanceState);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    canvasView = new MyView(this);
    setContentView(canvasView);

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0xFF00FF00);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.MITER);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(12);

    if (savedInstanceState != null) {
        Log.d("TAG", "Restoring any bitmaps...");
        byte[] imageByteArray = (byte[]) savedInstanceState.getSerializable("ByteArray");
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inMutable = true;
        Bitmap savedImage = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length, opt);
        canvasView.mBitmap = savedImage;
    }
}

在我的自定义视图 MyView 中,这是我在屏幕变化时旋转位图的代码:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    int orientation = display.getRotation();
    Log.d("CANVAS", "Rotation: " + orientation);
    if (mBitmap == null) {
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    } else {
        Matrix rotator = new Matrix();
        rotator.postRotate(orientation * 3);
        Bitmap rotatedBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), rotator, true);
        mCanvas = new Canvas(rotatedBitmap);
        mCanvas.drawBitmap(rotatedBitmap, 0, 0, mPaint);
    }
}

几乎所有其他内容都与 Fingerpaint 演示中的相同。我可以向下推以在屏幕上做标记,但是当我抬起手指时,我创建的路径不会应用于位图。

这里复制一个onTouchEvent()来说明(我没有修改):

   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;
        }

提前感谢您提供任何见解。我怀疑我对 Canvas 应该如何工作的理解不正确,因此我感到困惑!

[1] 完整的 Fingerpaint 演示在这里:https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java

【问题讨论】:

    标签: android android-canvas android-bitmap


    【解决方案1】:

    BitmapFactory.decodeByteArray() 会忽略您要求可变位图的选项,并为您提供一个不可变的位图,因为它是这样滚动的。

    https://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options)

    decodeByteArray
        Bitmap decodeByteArray (byte[] data, 
                        int offset, 
                        int length, 
                        BitmapFactory.Options opts)
        Decode an immutable bitmap from the specified byte array.
    

    您需要创建一个新的位图对象,使用其中一种方法来创建一个可变位图。然后将不可变位图绘制成可变位图。然后扔掉你加载的那个函数。

    不变性的原因是位图是根据您提供的字节创建的。因此,为了速度,它们由这些字节支持。它们是相同的记忆。实际位图对象的工作方式与此不同,您不能通过将这些字节从普通内存强制进入 GPU 来神奇地制作可变位图。您可以制作第二个位图对象并将数据绘制到第二个位图中。

    【讨论】:

      【解决方案2】:

      您必须控制活动的配置更改。

      <activity android:name=".MyActivity"
            android:configChanges="orientation|keyboardHidden"
            android:label="@string/app_name">
      

      更多详情请联系https://developer.android.com/guide/topics/resources/runtime-changes.html

      希望对你有帮助..

      【讨论】:

      • 那行不通。我确实在进行更改后尝试重建我的项目,但问题仍然存在。
      猜你喜欢
      • 2015-11-03
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      • 2013-08-04
      • 2012-07-21
      相关资源
      最近更新 更多