Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Custom View shows solid black after calling invalidate

In this code, I would like to draw a line between the top of two ImageViews. However, when running the app, the custom view is shown solid black after calling invalidate().

Here is my code:

public class ArrowView extends RelativeLayout {
    public Paint paint;
    public Bitmap eraser;
    public Canvas cacheCanvas;

    public float leftX;
    public float leftY;

    public float rightX;
    public float rightY;

    public boolean update = false;

    public ImageView iv_leftArrow;
    public ImageView iv_rightArrow;

    private int w;
    private int h;

    LayoutInflater mInflater;

    public ArrowView(Context context) {
        super(context);
        this.setWillNotDraw(false);
        mInflater = LayoutInflater.from(context);
        init();
    }

    public ArrowView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setWillNotDraw(false);
        mInflater = LayoutInflater.from(context);
        init();
    }

    public ArrowView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setWillNotDraw(false);
        mInflater = LayoutInflater.from(context);
        init();
    }

    @Override
    public void onSizeChanged(int w, int h, int oldW, int oldH) {
        this.w = w;
        this.h = h;
        super.onSizeChanged(w, h, oldW, oldH);
    }

    public void init() {
        View v = mInflater.inflate(R.layout.arrow_view, this, true);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(5);
        v.setBackgroundColor(Color.TRANSPARENT);

        eraser = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

        iv_leftArrow = (ImageView) v.findViewById(R.id.iv_leftarrow);
        iv_rightArrow = (ImageView) v.findViewById(R.id.iv_rightArrow);

        cacheCanvas = new Canvas();
        cacheCanvas.setBitmap(eraser);
    }

    public void setCoordinates(float leftX, float leftY, float rightX, float rightY) {
        this.leftX = leftX;
        this.leftY = leftY;
        this.rightX = rightX;
        this.rightY = rightY;
    }

    @Override
    public void onDraw(Canvas c) {
        super.onDraw(c);
        setCoordinates(iv_leftArrow.getX() + iv_leftArrow.getWidth() / 2, iv_leftArrow.getY(), iv_rightArrow.getX() + iv_rightArrow.getWidth() / 2, iv_rightArrow.getY() );
        if (update) {
            c.drawLine(leftX, leftY, rightX, rightY, paint);
            update = false;
        }
        cacheCanvas.drawPath(p, paint);
    }
}

Is there any reason why the custom view is showing as solid black after calling invalidate()?

like image 681
Pink Jazz Avatar asked May 31 '16 17:05

Pink Jazz


Video Answer


1 Answers

Usually, the system handles resizing, hiding, showing and a ton of other things for your widgets automatically but it sometimes has issues if the underlying buffer for drawn pixels or backing data has changed or is stale (you swap the image resource on a View or the raw dataset changes). This occurs because there is no way that the OS can know that the data changed in the specific manner that it did.

In these cases where you are dealing with drawing, you have to tell the system that its underlying data is not in a good state with Widget.invalidate() and the re-drawing gets queued on the main thread just as you mentioned. Depending on the system implementation and Android version what is tracked for changes by the system varies but what I normally do is assume that system resources (byte arrays, char arrays, resource indexes, manual drawing on the context) are not tracked and need an invalidate and everything else will be handled by the system.

Source : When it's necessary to execute invalidate() on a View?

like image 136
gopigoppu Avatar answered Oct 06 '22 09:10

gopigoppu