3

这是我第一次在 Android 中使用 Canvas 类。

我想要的是在画布上绘制不同颜色的线条。我有一个无法解决的问题。

在将颜色更改为红色并尝试用红色绘制第二条线后,我用黑色绘制第一条线,然后用黑色绘制的第一条线变为红色。

我使用的代码是:

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener 
{
    private Canvas      m_Canvas;

    private Path        m_Path;

    private Paint       m_Paint;

    ArrayList<Pair<Path, Paint>> paths = new ArrayList<Pair<Path, Paint>>();

    ArrayList<Pair<Path, Paint>> undonePaths = new ArrayList<Pair<Path, Paint>>(); 

    private float mX, mY;

    private static final float TOUCH_TOLERANCE = 4;

//  Bitmap canvasBackground;

    public DrawView(Context context) 
    {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);      
        this.setOnTouchListener(this);

        onCanvasInitialization();
    }      

    public void onCanvasInitialization()
    {
        m_Paint = new Paint();
        m_Paint.setAntiAlias(true);
        m_Paint.setDither(true);
        m_Paint.setColor(Color.parseColor("#37A1D1"));
        m_Paint.setStyle(Paint.Style.STROKE);
        m_Paint.setStrokeJoin(Paint.Join.ROUND);
        m_Paint.setStrokeCap(Paint.Cap.ROUND);
        m_Paint.setStrokeWidth(2);      

        m_Canvas = new Canvas();

        m_Path = new Path();
        Paint newPaint = new Paint(m_Paint);
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));

//      Bitmap canvas = BitmapFactory.decodeResource(getResources(), R.drawable.theme1_img_note).copy(Bitmap.Config.ARGB_8888, true);
//      canvasBackground = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888 );
//      m_Canvas = new Canvas(canvasBackground);        
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
    {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {      
        for (Pair<Path, Paint> p : paths) 
        {
            canvas.drawPath(p.first, p.second);
        }
    }

    public boolean onTouch(View arg0, 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;
    }

    private void touch_start(float x, float y) 
    {
        m_Path.reset();
        m_Path.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) 
    {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) 
        {
            m_Path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }
    private void touch_up() 
    {
        m_Path.lineTo(mX, mY);

        // commit the path to our offscreen
        m_Canvas.drawPath(m_Path, m_Paint);

        // kill this so we don't double draw            
        m_Path = new Path();
        Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));
    }

    public void onClickPenButton(int penWidth) 
    { 
        m_Paint.setStrokeWidth(penWidth);

        m_Path = new Path();
        Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));             
    }

    public void onClickPenColorButton(int penColor) 
    {       
        m_Paint.setColor(penColor);

        Paint newPaint = new Paint(m_Paint); // Clones the mPaint object
        paths.add(new Pair<Path, Paint>(m_Path, newPaint));
    }

    public void onClickUndo () 
    { 
        if (paths.size()>0) 
        { 
            undonePaths.add(paths.remove(paths.size()-1));
            invalidate();
        }
        else
        {

        }
    }

    public void onClickRedo ()
    {
        if (undonePaths.size()>0) 
        { 
            paths.add(undonePaths.remove(undonePaths.size()-1)); 
            invalidate();
        } 
        else 
        {

        }
    }
}
4

2 回答 2

4

您只有一个m_Paint对象,因此当onDraw被调用时,它将使用您设置的最后一种颜色绘制所有路径。

您可以存储每个路径的颜色,并且在绘制路径之前onDraw必须在内部设置颜色

编辑

这是一个快速解决方案的大纲,夜晚不是最优雅的:

  • AHashMap以路径为键,颜色为值
  • onClickPenColorButton将颜色保存到实例时说currentColor
  • touch_start您可以将路径对象与 推currentColorHashMap
  • 修改 onDraw 以获取每个路径的颜色。此代码仅用于说明,因此请根据需要进行修改。

    protected void onDraw(Canvas canvas)
    {                           
       for (Path p : paths)
       {  
          // Assuming your HashMap variable is pathColor
          m_Paint.setColor(pathColor.get(p));
    
          canvas.drawPath(p, m_Paint);
       }
    }
    
于 2013-01-31T12:29:44.850 回答
0

您必须为 PATH 和 PAINT 创建单独的对象,然后分别创建每个绘制对象的属性。然后在 onDraw 函数中,您必须为每个路径及其相应的绘制指定画布 drawCircle 方法。

例如,我有一个类似的问题,我花了一段时间才解决它。

首先,我想有一个可以画线的视图。代码是:

package com.example.ex13_singletouch

import android.content.Context
import android.graphics.*
import android.view.MotionEvent
import android.view.View

class SingleTouchView(context: Context): View(context) {    //AFTER COLON : WAS SOMETHING THAT WOULD BE RETURNED
    private val paint= Paint()
    private val path = Path()
    //TO CREATE THE X-Y POSITION OF THE FINGER ON THE SCREEN
    private var evenX: Float = 0F
    private var evenY: Float = 0F
    private var fingerDown = false  //CHECKS IF YOUR FINGER IS TOUCHING THE SCREEN OR NOT

    //INITIALIZATION
    init {
        paint.isAntiAlias = true
        paint.strokeWidth = 6F
        paint.strokeJoin = Paint.Join.ROUND
        paint.color = Color.BLACK
        paint.style = Paint.Style.STROKE
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        evenX = event!!.x
        evenY = event!!.y

        when(event.action){
            MotionEvent.ACTION_DOWN -> {
                fingerDown = true
                path.moveTo(evenX,evenY)
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                path.lineTo(evenX,evenY)    //WHEN YOU MOVE YOUR FINGER ON THE SCREEM, X AND Y KEEPS UPDATING AND IT DRAWS A LINE
            }
            MotionEvent.ACTION_UP -> {
                fingerDown = false
            }
            else -> return false
        }
        invalidate()    //JUMP TO THE ON DRAW TO DRAW SOMETHING THAT WE DEFINE
        return super.onTouchEvent(event)
    }

    //THIS FUNCTION SHAPES OUT THE THING WE DRAW. MEANS IT WILL MAKE A LINE STRAIGH OR WILL MAKE A CIRCLE ROUND
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas!!.drawPath(path, paint)
        if (fingerDown){
            canvas.drawCircle(evenX, evenY, 10F, paint)
        }
    }

}

然后我计划画出可以有 3 种不同颜色的线条——黑色、蓝色和红色。这是我更新的代码

package com.example.ex13_singletouch

import android.content.Context
import android.graphics.*
import android.view.MotionEvent
import android.view.View
import java.util.*
import kotlin.collections.ArrayList

class SingleTouchView(context: Context): View(context) {    //AFTER COLON : WAS SOMETHING THAT WOULD BE RETURNED
    //private val paint= Paint()
    private val paint1= Paint()
    private val paint2= Paint()
    private val paint3= Paint()
    //private val path = Path()
    private val path1 = Path()
    private val path2 = Path()
    private val path3 = Path()
    //TO CREATE THE X-Y POSITION OF THE FINGER ON THE SCREEN
    private var evenX: Float = 0F
    private var evenY: Float = 0F
    private var fingerDown = false  //CHECKS IF YOUR FINGER IS TOUCHING THE SCREEN OR NOT
    var colorControl = 1

    //INITIALIZATION
    init {
        paint1.isAntiAlias = true
        paint1.strokeWidth = 6F
        paint1.strokeJoin = Paint.Join.ROUND
        paint1.color = Color.BLACK
        paint1.style = Paint.Style.STROKE

        paint2.isAntiAlias = true
        paint2.strokeWidth = 6F
        paint2.strokeJoin = Paint.Join.ROUND
        paint2.color = Color.BLUE
        paint2.style = Paint.Style.STROKE

        paint3.isAntiAlias = true
        paint3.strokeWidth = 6F
        paint3.strokeJoin = Paint.Join.ROUND
        paint3.color = Color.RED
        paint3.style = Paint.Style.STROKE
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        evenX = event!!.x
        evenY = event!!.y

        when(event.action){
            MotionEvent.ACTION_DOWN -> {
                fingerDown = true
                //path.moveTo(evenX,evenY)
                if (colorControl==1){
                    path1.moveTo(evenX,evenY)
                }
                if (colorControl==2){
                    path2.moveTo(evenX,evenY)
                }
                if (colorControl==3){
                    path3.moveTo(evenX,evenY)
                }
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                //path.lineTo(evenX,evenY)    //WHEN YOU MOVE YOUR FINGER ON THE SCREEM, X AND Y KEEPS UPDATING AND IT DRAWS A LINE
                if (colorControl==1){
                    path1.lineTo(evenX,evenY)
                }
                if (colorControl==2){
                    path2.lineTo(evenX,evenY)
                }
                if (colorControl==3){
                    path3.lineTo(evenX,evenY)
                }
            }
            MotionEvent.ACTION_UP -> {
                fingerDown = false
                if (colorControl==3){
                    colorControl=1
                }
                else {
                    colorControl++
                }
            }
            else -> return false
        }
        invalidate()    //JUMP TO THE ON DRAW TO DRAW SOMETHING THAT WE DEFINE
        return super.onTouchEvent(event)
    }

    //THIS FUNCTION SHAPES OUT THE THING WE DRAW. MEANS IT WILL MAKE A LINE STRAIGH OR WILL MAKE A CIRCLE ROUND
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas!!.drawPath(path1, paint1)
        canvas!!.drawPath(path2, paint2)
        canvas!!.drawPath(path3, paint3)
    }
}

您可以查看这两个代码之间的差异,看看我所做的更改。我希望这是有帮助的。

于 2021-10-21T22:58:54.867 回答