【问题标题】:How can I override onDraw so that I take what would have been drawn (as a bitmap) and transform it?我怎样才能覆盖 onDraw 以便我将绘制的内容(作为位图)并转换它?
【发布时间】:2018-09-03 06:43:51
【问题描述】:

下面的方法有效,但不幸的是,这种方法涉及创建整个屏幕大小的位图 - 而不仅仅是绘制到的区域。如果我使用它来绘制 UI 元素,则会为每个 UI 元素重绘。这可以更有效地完成吗?

@Override
protected void onDraw(Canvas canvas) {
    //TODO: Reduce the burden from multiple drawing
    Bitmap bitmap=Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
    Canvas offscreen=new Canvas(bitmap);
    super.onDraw(offscreen);
    //Then draw onscreen
    Paint p=new Paint();
    p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
    canvas.drawBitmap(bitmap, 0, 0, p);
}

【问题讨论】:

    标签: android


    【解决方案1】:

    下面的代码会更有效率。

    public class MyView extends TextView{
        private Canvas offscreen;
    
        public MyView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyView(Context context) {
            super(context);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //We want the superclass to draw directly to the offscreen canvas so that we don't get an infinitely deep recursive call
            if(canvas==offscreen){
                super.onDraw(offscreen);
            }
            else{
                //Our offscreen image uses the dimensions of the view rather than the canvas
                Bitmap bitmap=Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
                offscreen=new Canvas(bitmap);
                super.draw(offscreen);
                //Create paint to draw effect
                Paint p=new Paint();
                p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
                //Draw on the canvas. Fortunately, this class uses relative coordinates so that we don't have to worry about where this View is actually positioned.
                canvas.drawBitmap(bitmap, 0, 0, p);
            }
        }
    }
    

    【讨论】:

    • 如果在draw方法中创建了新的对象,会不会造成太多的垃圾回收?
    • 确实,在onDraw方法之外创建位图和绘画
    【解决方案2】:

    您是否尝试过将您创建的位图的大小更改为仅等于剪辑边界而不是给定画布的整个大小?我不知道是不是所有视图都是这种情况,但我发现某些视图的 onDraw 方法被赋予了一个与屏幕一样大的画布,而不管内容的实际大小如何。然后它会剪切画布,将其限制在仅左上角,在那里绘制,然后在实际准备好显示整个布局时将该部分转换到屏幕上的其他位置。换句话说,尽管它有一个整个屏幕大小的画布,但它实际上只使用了一小块。所以你可以尝试做的是而不是使用

    Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), ...)
    

    你可以试试

    Rect rect = canvas.getClipBounds();
    int width = rect.width();
    int height = rect.height();
    Bitmap bitmap = Bitmap.createBitmap(width, height, ...); 
    

    这样您就可以减少使用比必要的大得多的位图的开销。注意:我实际上没有尝试过这样做,所以它可能不起作用,但值得一试。

    【讨论】:

    • 我认为getClipBounds 方法给出了正确的尺寸,但由于我不确定我是否使用ViewgetWidthgetHeight 方法。这实际上不起作用,因为 onDraw 方法使用某种偏移量。我设法使用不使用偏移量的Viewdraw 方法解决了这个问题。请注意,Canvas 的绘制方法都使用偏移量。起初我觉得这很令人困惑,但仔细想想,这一切都说得通。
    【解决方案3】:

    我遇到过类似的情况,canvas.getWidth() 和 canvas.getHeight() 返回整个屏幕的宽度和高度,而不是视图本身。

    尝试改用以下内容:

    Bitmap bitmap=Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
    

    对于我来说,getWidth() 和 getHeight() 返回我的视图尺寸。祝你好运!

    【讨论】:

      猜你喜欢
      • 2011-01-10
      • 1970-01-01
      • 2019-04-28
      • 1970-01-01
      • 2022-11-25
      • 2013-07-22
      • 1970-01-01
      • 2022-11-29
      • 2018-03-25
      相关资源
      最近更新 更多