从画布清除油漆而不清除背景图像 - Android

时间:2014-09-04 18:20:52

标签: android bitmap android-canvas

我有一张带背景图片的画布。我需要知道是否可以清除此画布上的油漆以进行重绘而不清除其背景图像。这是我的例子和迄今为止的结果。

JAVA

public void setCanvas() {
    if(mFile != null && mFile.exists()) {
        mPictureBitmap = BitmapFactory.decodeFile(mFile.getAbsolutePath());
        mBitmap = Bitmap.createScaledBitmap(mPictureBitmap, mImageView.getWidth(), mImageView.getHeight(), false);
        mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mCanvas = new Canvas(mBitmap);

        mImageView.setImageBitmap(mBitmap);
        mImageView.setOnTouchListener(this);
    }
}

private void draw() {
    mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); // THIS LINE CLEARS

    int lastIndex = mCordHashMap.size() - 1;
    int index = 0;

    for (LinkedHashMap.Entry<String, ArrayList<Circle>> entry : mCordHashMap.entrySet()) {
        ArrayList<Circle> coords = new ArrayList<Circle>();
        coords = entry.getValue();
        Path path = new Path();
        String key = entry.getKey();
        String surface = getSurfaceFromKey(key);
        changePaint(surface);

        if (coords.size() < 3) {
            for (Circle c : coords) {
                mCanvas.drawCircle(c.getmX(), c.getmY(), RADIUS, mCirclePaint);
            }
        } else {
            for (Circle c : coords) {
                if (c == coords.get(0)) {
                    path.moveTo(c.getmX(), c.getmY());
                } else {
                    path.lineTo(c.getmX(), c.getmY());
                }
            }

            path.close();
            mCanvas.drawPath(path, mPaint);
            mCanvas.drawPath(path, mStrokePaint);

        }

        if (index == lastIndex && !mSpecificPathSelected) {
            for (Circle c : coords) {
                mCanvas.drawCircle(c.getmX(), c.getmY(), RADIUS, mCirclePaint);
                mCanvas.drawCircle(c.getmX(), c.getmY(), RADIUS, mCircleStrokePaint);
            }
        }
        mImageView.invalidate();
        index++;
    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <ExpandableListView
        android:id="@+id/surfaceList"
        android:background="@color/light_grey"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight=".20" />

    <ImageView
        android:id="@+id/drawContainer"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight=".80" 
        android:contentDescription="@string/app_name"/>

</LinearLayout>

因此上面的代码会将图片加载到我的Canvas中。然后每当我触摸Canvas时,它会绘制一个圆圈,最终形成圆圈之间的路径。然而,当我开始添加更多的圆圈和路径时,它会重新绘制,这看起来很糟糕。

现在我可以用这条线清除画布上的油漆。

mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

但是我也失去了Bitmap我设置的背景,现在我的背景是黑色的。那么,我如何保留我的背景图像,但清除我的油漆?这是可能的,还是我必须使用两个Canvas之类的工作?

我已经尝试过以下几种变体。

1) mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

2) mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
   mCanvas.drawBitmap(mBitmap, 0, 0, mPaint);

3) mBitmap.eraseColor(Color.TRANSPARENT);
   mCanvas.drawBitmap(mBitmap, 0, 0, mPaint);

感谢任何帮助

3 个答案:

答案 0 :(得分:3)

据我所知,Canvas并不包含图层。所以你不能删除一层(油漆)而留下另一层(背景)。我相信你应该使用两个画布,甚至是画布和ImageView来保存背景。然后,当您要导出图像时,将画布内容与背景组合。

答案 1 :(得分:3)

我终于明白了。我能够在ImageViews中使用两个RelativeLayout堆叠。将ImageViews堆叠在一起,然后将ImageViews设置为相同的图片,但将Bitmaps分开。现在,最上面的一个充当你的前景,你的底部充当你的背景。现在,您可以在顶部绘制,同时清除背景,而不会影响底部背景。关键是属性yourImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);,它关闭硬件加速并允许您的背景实际呈现为透明。如果没有将此属性应用于您的视图,您将拥有完全覆盖底部ImageView的黑色或白色背景,这使其完全无用。

<强> XML

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <ExpandableListView
        android:id="@+id/surfaceList"
        android:background="@color/light_grey"
        android:layout_width="250dp"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/background"
        android:layout_width="match_parent"
        android:layout_toRightOf="@+id/surfaceList"
        android:layout_height="match_parent"
        android:contentDescription="@string/app_name"/>

    <ImageView
        android:id="@+id/foreground"
        android:layout_width="match_parent"
        android:layout_toRightOf="@+id/surfaceList"
        android:layout_height="match_parent"
        android:contentDescription="@string/app_name"/>

</RelativeLayout>

<强> JAVA

public void setCanvas() {
    if(mFile != null && mFile.exists()) { // check for null
        mFirstBitmap = BitmapFactory.decodeFile(mFile.getAbsolutePath()); // get bitmap from directory
        mSecondBitmap = Bitmap.createScaledBitmap(mPictureBitmap, mImageView.getWidth(), // size bitmap mImageView.getHeight(), false);
        mSecondBitmap = mSecondBitmap .copy(Bitmap.Config.ARGB_8888, true); // make bitmap mutable so it can be applied to the canvas
        mFirstBitmap = mSecondBitmap .copy(Bitmap.Config.ARGB_8888, true); // make second bitmap from copy, also mutable
        mCanvas = new Canvas(mSecondBitmap ); //create your canvas from 2nd bitmap
        mImageView.setImageBitmap(mSecondBitmap ); // set this imageview to 2nd bitmap
        mImageView2.setImageBitmap(mFirstBitmap); //set this imageview to 1st bitmap

        mImageView.setOnTouchListener(this); // set on touch listener
        mImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); // IMPORTANT set hardware acceleration off with this line. Otherwise your view's background will NOT be transparent
        mImageView.bringToFront(); // bring this imageview to the front, making it your foreground
    }
}

希望这可以为其他人节省大量时间。

答案 2 :(得分:1)

如果你没有使用imageView,那就是另一种更简单的解决方案:

我有一个新的Bitmap(mBackgroundBitmap);新的Canvas(mBackgorundCanvas),将mBackgroundBitmap作为mBackgroundCanvas,并在每个onDraw方法上首先我的背景位图:

canvas.drawBitmap(mBackgroundBitmap, offSetX, offSetY, mBitmapPaint);

然后我开始绘制我的实际位图:

canvas.drawBitmap(mBitmap, offSetX, offSetY, mBitmapPaint);

我想这不是内存有效的解决方案(我的意思是有两个位图不是非常酷或令人愉快,但是我们很多人都没有使用大图像,而是(至少我)从片段创建我的背景然后在X和Y方向上平铺它。

如果我的回答很荒谬,不要评判我,我只是一个菜鸟。

相关问题