【问题标题】:Semi-transparent eraser brush on canvas画布上的半透明橡皮刷
【发布时间】:2017-02-20 21:27:57
【问题描述】:

我正在尝试将半透明橡皮刷写入我正在开发的应用程序中,但发现根据其实现方式会出现两个问题。希望有一个我可以指出的解决方法。

代码示例位于 mono droid / xamarin 中

所以,通常情况下,我有一个在绘图画布上绘制路径的设置。我的视图的OnDraw 方法绘制它的基本位图,然后在其上绘制我的路径。

    // Canvas is set up elsewhere
    canvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
    DrawCanvas.SetBitmap(canvasBitmap);


    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);

        // Draw the saved canvas bitmap
        canvas.DrawBitmap(canvasBitmap, 0, 0, canvasPaint);

        // On top of that draw the current path
        canvas.DrawPath(DrawPath, DrawPaint);
    }



    public bool OnTouch(View view, MotionEvent ev)
    {
        float touchX = ev.GetX();
        float touchY = ev.GetY();


        switch (ev.Action)
        {
            case MotionEventActions.Down:

                if (Editable)
                {
                    // I've removed a bunch of code here but it basically
                    // moves the path start to the touch point and sets
                    // up the brush to start erasing. It does set the
                    // porterduff mode to dstOur
                    DrawPaint.SetMaskFilter(null);
                    DrawPaint.SetXfermode( new PorterDuffXfermode(PorterDuff.Mode.DstOut));

                    DrawPath.MoveTo(touchX, touchY);

                } else { return false;  }
                break;

            case MotionEventActions.Move:

                // Just draws a line to the new touch coordinates
                DrawPath.LineTo(touchX, touchY);

                break;
            case MotionEventActions.Up:
            case MotionEventActions.Cancel:

                // saves some data about the path and draws to the drawing canvas.
                DrawCanvas.DrawPath(DrawPath, DrawPaint);

                // Recycle it
                DrawPath.Reset();

                break;

        }
        return true;
    }

所以有两种方法可以在绘制橡皮擦线时绘制它。第一种是在绘图画布上绘图(写入canvasBitmap),第二种是直接在OnDraw 提供的canvas 上绘图。

我的问题如下:

如果我在DrawCanvas 上绘图,我会得到一种堆叠效果,擦除的线条会逐渐变得越来越透明。这是可以理解的,因为在每个OnDraw 循环期间,橡皮擦路径都被烘焙到canvasBitmap 中。

如果我直接在OnDraw 提供的canvas 上绘图,我会遇到“black line”问题,这也是有一定道理的,因为它会擦除什么都没有。当在Up 事件中将路径绘制到canvasBitmap 时,一切看起来都正确,并且有一条漂亮的半透明橡皮擦线。

理想情况下,对于“black line”问题,我不知道有一个不同的解决方案,但我找不到任何东西。我还尝试考虑缓存canvasBitmap 的方法,并且在绘制事件正在进行时使用它而不是Move 事件绘制到的活动副本。

有没有人可以看一下可能会提出解决方案的东西? Java 很好,因为它很容易移植到 c#。

提前非常感谢! 奈杰尔

【问题讨论】:

    标签: android android-canvas


    【解决方案1】:

    在没有比我更有经验/更聪明的人提出建议的情况下,我以可怕的方式解决了这个问题。在我继续寻找更聪明的方法时,它可能仍然对其他人有帮助。

    Down 事件发生时,我将位图的一个干净副本抓取到一个临时变量中。在每个OnDraw 事件中,我都会重新绘制干净的位图,然后在其上绘制擦除路径。

    可怕的是,每个OnDraw 事件中都有一个位图复制方法,以确保不会发生重复的擦除路径。

    OnDraw( Canvas canvas )
    {
                tempBitmap.Recycle();
                tempBitmap = _drawingBitmap.Copy(_drawingBitmap.GetConfig(), true);
    
                DrawCanvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear);
                DrawCanvas.DrawBitmap(tempBitmap, 0, 0, DrawPaint));
                DrawCanvas.DrawPath(DrawPath, DrawPaint);
    }
    

    位图回收显然非常关键。在触摸侦听器中的.Up 事件上,它会再次循环,然后将变量设为空。

    不漂亮,但它有效。

    非常感谢任何更好的想法!

    【讨论】:

      猜你喜欢
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-19
      • 1970-01-01
      • 2014-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多