Android更改 Canvas 背景颜色而不会丢失任何绘图

标签 android android-canvas

我正在尝试找到一种方法来设置 Canvas 背景,使用从自定义颜色选择器中拾取的颜色,而不删除 Canvas 上的任何绘图。我正在尝试创建一个可以在 Canvas 上绘制并将其保存为 png 的应用程序。但是当我为当前 Canvas 设置新背景时,所有绘图都消失了。我正在使用这样的东西:

mCanvas.drawColor(picker.getColor());

我有什么想法可以让事情正常运作吗?

最佳答案

已经对您的问题给出的答案都指向正确的方向:您确实需要将背景色 block 和前景绘图分离到不同的图层中,然后合并它们,然后再将它们全部保存在一个 .png 文件中。这也是 Adob​​e Photoshop 工作流程的设计方式......如果我们考虑一下,它确实有意义:以 MsPaint 之类的软件为例:因为它不使用图层,所以它必须依赖诸如 floodfill 算法之类的东西来完成(尽管以不完整的方式)远程类似于背景更改的事情......

实现这种事情的一种方法是实例化由 2 个不同位图支持的 2 个 Canvas 对象。第一个 Canvas-Bitmap 对将用于前景绘图,第二个 Canvas-Bitmap 对将用于合并图层绘图(即前景绘图 + 背景色 block )。然后第二个位图将在您需要保存时保存到 .png 文件中。这样,我们的第一个 Canvas-Bitmap 对存储了您的前景信息,如果需要更改背景颜色,这些信息不会被破坏。每次进行操作时,图层都可以合并到第二个 Canvas-Bitmap 对中,以便始终有一个具有正确内容的 Bitmap 可以随时保存。

这是我制作的一个自定义 View ,目的是让这个方法更清晰。它实现了一个简单的 View ,用于使用手指在触摸屏上绘制一条蓝线,背景颜色根据所述手指的 X-Y 位置而变化,以演示背景颜色的变化,而无需完整实现固有的不必要的代码复杂性使用色轮/菜单/除其他外:

package com.epichorns.basicpaint;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Paint.Style;
import android.view.View;

public class PaintView extends View{

    Bitmap mMergedLayersBitmap=null; //Note: this bitmap here contains the whole of the drawing (background+foreground) to be saved.
    Canvas mMergedLayersCanvas=null;

    Bitmap mBitmap = null; //bitmap onto which we draw our stuff
    Canvas mCanvas = null; //Main canvas. Will be linked to a .bmp file
    int mBackgroundColor = 0xFF000000; //default background color
    Paint mDefaultPaint = new Paint();

    Paint mDrawPaint = new Paint(); //used for painting example foreground stuff... We draw line segments.
    Point mDrawCoor = new Point(); //used to store last location on our PaintView that was finger-touched

    //Constructor: we instantiate 2 Canvas-Bitmap pairs
    public PaintView(Context context, int width, int height) {
        super(context);
        mMergedLayersBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
        mMergedLayersCanvas = new Canvas(mMergedLayersBitmap);

        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    //Change background color
    public void changeColor(int newColor){
        mBackgroundColor = newColor;
        invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards
    }

    //Called by user of PaintView in order to start a painting "stroke" (finger touching touch-screen): stores the 
    //location of the finger when it first touched the screen
    public void startDraw(int x, int y, int radius, int color){
        mDrawPaint.setColor(color);
        mDrawPaint.setStyle(Style.STROKE);
        mDrawPaint.setStrokeWidth(radius);
        mDrawCoor.x = x;
        mDrawCoor.y = y;        
    }

    //Called by user of PaintView when finger touching touch-screen is moving (must be called after a startDraw, 
    //as the latter initializes a couple of necessary things)
    public void continueDraw(int x, int y){
        mCanvas.drawLine(mDrawCoor.x, mDrawCoor.y, x, y, mDrawPaint);
        mDrawCoor.x = x;
        mDrawCoor.y = y;
        invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards
    }

    //Merge the foreground Canvas-Bitmap with a solid background color, then stores this in the 2nd Canvas-Bitmap pair.
    private void mergeLayers(){
        mMergedLayersCanvas.drawColor(mBackgroundColor);
        mMergedLayersCanvas.drawBitmap(mBitmap, 0, 0, mDefaultPaint);
    }

    @Override
    public void onDraw(Canvas canvas){
        mergeLayers();
        canvas.drawBitmap(mMergedLayersBitmap, 0, 0, mDefaultPaint);
    }

}

为了测试这个 View ,这里有一个使用PaintView类的测试Activity。这两个文件在 Android 项目中都是自给自足的,因此您可以毫不费力地在真实设备上对其进行测试:

package com.epichorns.basicpaint;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;


import com.epichorns.basicpaint.PaintView;
public class BasicPaintActivity extends Activity {
    PaintView mPaintView=null;
    LinearLayout mL = null;
    boolean mIsDrawing=false;
    int mBackgroundColor = 0xFF000000;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Display display = getWindowManager().getDefaultDisplay();       
        final float dispWidth = (float)display.getWidth();
        final float dispHeight = (float)display.getHeight();

        mPaintView = new PaintView(this, display.getWidth(), display.getHeight());    
        mPaintView.changeColor(mBackgroundColor);
        mPaintView.setOnTouchListener(new View.OnTouchListener(){

            public boolean onTouch(View v, MotionEvent event) {

            if(event.getAction()==MotionEvent.ACTION_DOWN){
                    mPaintView.startDraw((int)event.getX(), (int)event.getY(), 6, 0x806060FF);              
                    mIsDrawing=true;
                    return true;
                }
                else if(event.getAction()==MotionEvent.ACTION_UP){
                    mIsDrawing=false;
                    return true;
                }
                else if(event.getAction()==MotionEvent.ACTION_MOVE){
                    if(mIsDrawing){

                        //To demonstrate background change, change background color depending on X-Y position
                        int r = (int)(255f*event.getX()/dispWidth);
                        int g = (int)(255f*event.getY()/dispHeight);
                        mBackgroundColor = Color.argb(0xFF, r,g, 0x00);
                        Log.d("DEBUG1", "Color channels: (r, g) = ("+String.valueOf(r)+", "+String.valueOf(g)+")");
                        mPaintView.changeColor(mBackgroundColor);

                        //now, draw stuff where finger was dragging...
                        mPaintView.continueDraw((int)event.getX(), (int)event.getY());
                        return true;
                    }
                    else{
                        return false;
                    }

                }

                return false;
            }

        });

        setContentView(mPaintView);
    }




}

关于Android更改 Canvas 背景颜色而不会丢失任何绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10268724/

相关文章:

android - 选择栏以单击空白区域。如何避免在单击空白区域时突出显示栏?

android - SensorManager.getOrientation 给出非常不稳定的结果

java - 拉伸(stretch)/收缩 Canvas

android - Android Looper 线程是否使用处理能力?

android - 在 Activity 过渡动画期间保持 Action Bar 稳定

java - 如何在android图库中显示10分钟前拍摄的图像?

android - 关于android中的lineargradient

android - imageView.setImageBitmap(Bitmap) 极度减慢我的应用程序

java - 多种颜色/笔画手势和在同一个 GestureOverlayView 中持续绘图

android - WebView.draw(canvas) 有时会在某些设备上的 Android Lollipop 5.0+ 中崩溃 - 致命信号 11 (SIGSEGV)