【问题标题】:Clear paint from canvas without clearing background image - Android从画布上清除油漆而不清除背景图像 - Android
【发布时间】:2014-09-04 18:20:52
【问题描述】:

我有一个带有背景图像的画布。我需要知道是否可以在不清除其背景图像的情况下清除此画布上的油漆以进行重绘。这是我的示例和到目前为止的结果。

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

感谢任何帮助

【问题讨论】:

标签: android bitmap android-canvas


【解决方案1】:

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

【讨论】:

  • 这是有道理的。如果您仔细观察,我实际上是在使用ImageView 并将位图设置为其 src 内容,但显然这对我没有任何好处。 "I believe you should be using either two canvases, or even the paint canvas and an ImageView to hold the background. Then when you want to export the image combine the canvas contents with the background."如果您有时间,请发布其中任何一个的示例。
  • 好吧,所以我一直在努力寻找一些东西。您是否有成功使用 imageview 作为背景和/或两个画布的人的链接?
  • 抱歉,在工作。我只是在等待服务器部署时浏览 SO。今晚我会更深入地研究一下。
  • 谢谢,它让我发疯了一段时间,实际上我尝试使用多个画布、图像视图、porterduff 绘制模式的所有内容,都会导致黑色画布背景覆盖我的图像视图并阻挡图片
  • 今天又回来了,如果你在我做之前找到任何东西,请告诉我。我目前正在研究自定义 ImageView,并覆盖 onDraw 方法,看看是否有帮助。
【解决方案2】:

我终于明白了。我能够使用两个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
    }
}

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

【讨论】:

    【解决方案3】:

    如果您不使用 imageView,还有另一个更简单的解决方案:

    我有一个新的位图(mBackgroundBitmap);新的 Canvas(mBackgorundCanvas),将 mBackgroundBitmap 分配给 mBackgroundCanvas,并且在每个 onDraw 方法上首先我 dar 我的背景位图:

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

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

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

    我猜这不是节省内存的解决方案(我的意思是有两个位图不是很酷或不愉快,但是我们中的许多人不使用大图像,而是(至少我)从片段创建我的背景,然后在 X 和 Y 方向平铺。

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

    【讨论】:

    • 我喜欢你的回答,虽然从记忆的角度来看它可能效率不高,但它又好又简单。
    猜你喜欢
    • 1970-01-01
    • 2016-11-23
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    • 2012-03-14
    • 2013-05-15
    相关资源
    最近更新 更多