How can I override onDraw so that I take what woul

2020-02-09 11:34发布

The method below works, but it unfortunately, this method involves creating a bitmap the size of the entire screen - not just the area that is drawn to. If I use this to draw UI elements, it is redrawn for each UI element. Can this be done more efficiently?

@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
3条回答
▲ chillily
2楼-- · 2020-02-09 12:27

I encountered something similar, where canvas.getWidth() and canvas.getHeight() returns the width and height of the whole screen instead of the view itself.

Try to use the below instead:

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

For my case, getWidth() and getHeight() returns me the dimensions of my view. Good luck!

查看更多
欢心
3楼-- · 2020-02-09 12:29

The following code will be much more efficient.

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);
        }
    }
}
查看更多
啃猪蹄的小仙女
4楼-- · 2020-02-09 12:31

Have you tried changing the size of the bitmap you create, to be only equal to the clip bounds rather than the entire size of the given canvas? I don't know if this is the case with all Views, but I found that the onDraw method for some Views is given a canvas as big as the screen, regardless of the actual size of the content. It then clips the canvas, restricting it to the top left corner only, draws there and then translates that part to somewhere else on the screen when it's actually ready to display the whole layout. In other words, despite it having a canvas the size of the whole screen, it only actually uses a small piece of it. So what you could try doing is instead of using

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

you could try

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

That way you reduce the overhead of working with a much larger bitmap than necessary. Note: I haven't actually tried doing this so it might not work, but it's worth trying.

查看更多
登录 后发表回答