在Android onDraw()上直接绘制画布和绘制位图然后画布之间的区别

时间:2013-06-10 13:36:15

标签: android android-canvas android-custom-view

我正在编写一个显示信号的自定义视图。为了缩短我的onDraw()时间,我将目前为止在Bitmap中绘制的所有内容都缓存,并在每次onDraw()调用中追加到它。通过这样做,我可以节省大量的时间,因为我只需要一次绘制一些修复,而不是重做整个事情。

但有些东西困扰着我 - 看起来直接绘制到提供的画布提供的绘图比首先在位图上绘制然后在画布上绘制位图更准确。通过查看下图的下半部分,您可以看到差异:

Look at the lower part of the signal to see difference - there are the same drawLine calls

我上传了一个显示https://github.com/gardarh/android-uglybitmapdrawing/差异的演示项目,但相关代码如下:

@Override
public void onDraw(Canvas canvas) {
    if(cachedBitmap == null) {
        cachedBitmap = Bitmap.createBitmap(getWidth(), 200, Config.ARGB_8888);
        cachedCanvas = new Canvas(cachedBitmap);
    }

    for(int i = 0; i < COORDS.length; i++) {
        float[] curCoords = COORDS[i];
        canvas.drawLine(curCoords[0], curCoords[1], curCoords[2], curCoords[3], linePaint);
        cachedCanvas.drawLine(curCoords[0], curCoords[1], curCoords[2], curCoords[3], linePaint);
    }
    canvas.drawBitmap(cachedBitmap, 0, 120, null);
}

为什么这两条迹线不一样,更重要的是,如何让下面的迹线看起来像上面的迹线?

3 个答案:

答案 0 :(得分:3)

Android framework API为简单动画提供2D绘图API,不需要进行重大动态更改。  使用这些API有两种实现方式。

<强> 1。绘制视图
    2.在画布上绘图

1.绘制圆圈以查看

                当UI不需要在应用程序中进行动态更改时,绘制到视图是更好的选择。 这可以通过扩展View类并定义 onDraw()回调方法来实现。
 使用为您的所有绘图提供的画布,
使用各种Canvas.draw ...()方法(例如:canvas.drawCircle(x / 2,y / 2,radius,paint);)。 onDraw()是最初绘制视图时调用的回调方法。

以下是绘制圆圈的简单示例代码: -

MainActivity.java

 public class MainActivity extends Activity {

     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(new MyView(this));
     }

     public class MyView extends View {
         public MyView(Context context) {
              super(context);
              // TODO Auto-generated constructor stub
         }

         @Override
         protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            int x = getWidth();
            int y = getHeight();
            int radius;
            radius = 100;
            Paint paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(Color.WHITE);
            canvas.drawPaint(paint);
            // Use Color.parseColor to define HTML colors
            paint.setColor(Color.parseColor("#FB9J2F"));
            canvas.drawCircle(x / 2, y / 2, radius, paint);
        }
     } }

<强> 2。在画布上绘制矩形

要绘制动态2D图形,您的应用程序需要定期重新绘制自己,在画布上绘图是更好的选择。 Canvas可以作为界面,用于绘制图形的实际表面。

如果需要创建新的Canvas,则必须定义实际执行绘图的位图。 Canvas总是需要位图。

以下示例说明绘制矩形: -

  activity_main.xml

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

<强> MainActivity.java

public class MainActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Paint paint = new Paint();
        paint.setColor(Color.parseColor("#DD4N5C"));
        Bitmap bitmap = Bitmap.createBitmap(512, 800, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap); 
        canvas.drawRect(150, 150, 250, 250, paint); 
        LinearLayout layout = (LinearLayout) findViewById(R.id.mylayout);
        layout.setBackgroundDrawable(new BitmapDrawable(bitmap));   
     }

     }

答案 1 :(得分:2)

差异的原因是画布绘制是通过硬件加速(GPU)完成的,位图绘制是由软件(CPU)完成的。如果禁用硬件加速,它们将完全相同。 如果将X坐标乘以10,您将看到差异在于线的连接方式。这些是小的一个像素差异,我不打扰他们。我不确定哪一个更准确,它们看起来只是略有不同的实现。

答案 2 :(得分:0)

我不同意你通过去位图路线节省了很多。您可以考虑一种存储绘制信号的数据结构,并将其转换为可以序列化/反序列化的JSON对象。 至于你的问题,这是一个有根据的猜测,但它更多地与绘制信号的重新缩放有关,因为你在创建位图时没有使用getHeight()。