简体   繁体   English

Android:为什么旋转屏幕后不能在画布位图上绘画?

[英]Android: Why can't I paint on my canvas bitmap after rotating screen?

I am using Android's Fingerpaint demo[1] to experiment with Canvas and Bitmaps. 我正在使用Android的Fingerpaint演示[1]来测试Canvas和Bitmap。 I want to draw an object on a screen, and continue drawing the object after the screen has rotated. 我想在屏幕上绘制对象,并在屏幕旋转后继续绘制对象。 The Fingerpaint demo erases the screen after a screen rotation - I want to preserve the contents of the screen and just rotate it along with the screen. 在屏幕旋转后,Fingerpaint演示会擦除屏幕-我想保留屏幕内容,并随屏幕一起旋转。

With my code, I can rotate the screen and the image I've drawn. 使用我的代码,我可以旋转屏幕和绘制的图像。 But I'm no longer able to add any additional path markings to the bitmap. 但是我不再能够向位图添加任何其他路径标记。 It becomes like a read-only Bitmap. 它变得像只读位图。 Does anyone know what I am I doing wrong? 有人知道我在做什么错吗?

Here's the code where I save the image and restore it after a rotation. 这是我保存图像并在旋转后还原它的代码。 Notice that I am saving it as a PNG in a byte array (in onSaveInstanceState()) and then creating a new Bitmap from that byte array in onCreate() (I think this is okay?): 请注意,我将其另存为字节数组(在onSaveInstanceState()中)为PNG,然后从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;
    }
}

In my custom view, MyView, here's the code where I rotate the bitmap when the screen changes: 在我的自定义视图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);
    }
}

Just about everything else is the same as in the Fingerpaint demo. 几乎所有其他内容都与Fingerpaint演示中的相同。 I can push down to make markings on the screen, but when I lift my finger the path I've created is not applied to the bitmap. 我可以按下以在屏幕上进行标记,但是当我抬起手指时,我创建的路径不会应用于位图。

Here's a duplication of the onTouchEvent() to illustrate (I did not modify it): 这是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;
        }

Thanks in advance for any insight. 预先感谢您的任何见解。 I suspect my understanding of how Canvas should work is not correct, and hence my confusion! 我怀疑我对Canvas应该如何工作的理解是不正确的,因此我感到困惑!

[1] The full Fingerpaint demo is here: https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java [1]完整的Fingerpaint演示位于此处: https : //android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java

BitmapFactory.decodeByteArray() ignores the option where you asked for a mutable bitmap and gives you one that isn't mutable because that's how it rolls. BitmapFactory.decodeByteArray()忽略了您要求可变位图的选项,并为您提供了一个不可变的位图,因为它就是这样滚动的。

https://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options) 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.

You need to create a new bitmap object, using one of the ways to create a mutable bitmap. 您需要使用一种创建可变位图的方法之一来创建一个新的位图对象。 Then paint the immutable bitmap into the mutable one. 然后将不可变位图绘制为可变位图。 Then toss the one you loaded with that function. 然后把那个加载了那个功能的那个扔掉。

The reason for the immutability is that the bitmap was created from those bytes you gave it. 不可变性的原因是,位图是根据您提供的字节创建的。 So for speed they are backed by those bytes. 因此,为了提高速度,它们由这些字节支持。 They are the same memory. 它们是相同的记忆。 And the way actual bitmap objects work is different than that, and you can't just magically make a mutable bitmap by forcing those bytes from normal memory into the GPU. 实际的位图对象的工作方式与此不同,您不能仅仅通过将正常内存中的这些字节强制进入GPU来神奇地制作可变的位图。 You can just make a second bitmap object and paint the data into that second bitmap. 您可以只创建第二个位图对象并将数据绘制到该第二个位图中。

You must control your configuration change for the activity. 您必须控制活动的配置更改。

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

For more details just go for https://developer.android.com/guide/topics/resources/runtime-changes.html 有关更多详细信息,请访问https://developer.android.com/guide/topics/resources/runtime-changes.html

Hope it helps.. 希望能帮助到你..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM