Search code examples
androidcanvasmotionevent

Custom View: Redraw view canvas on Press


I'm working on custom view, which have to draw custom canvas when pressed and other if not. I have basically overriden only methods onMeasure and onDraw. In Constructor I have set: setFocusable(true) and setDrawingCacheEnabled(true)

public class CircularImageView extends ImageView{
    //...
    @Override
    protected void onDraw(Canvas canvas) {
        // ...
        if (isPressed() || isSelected() || isFocused()){
            // code when pressed
        }
        else{
            // otherwise
        }
    }
}

I want this effect: view looks like pressed after onDown and like non-pressed after onUp/onCancel motion event. Normally I was using <selector> but now i have to do a little bit of work with canvas. (one draws circle around view, other some background effects)

How can I set canvas for different press states?


Solution

  • Thanks to pskink I was able to create complete solutions so here is it.

    If you want to create custom view in which have to be your custom drawings for different touch states (pressed, selected, focused etc.) and you didn't know whether this view will be placed inside other View that can intercept touch events or the view structure is even more difficult. You should implement the behavior as follows

    1. Create custom Drawable
    2. in overriden method isStateful() return true value (needed to hold different states)
    3. override onStateChange method and call invalidateSelf() if state was changed.
    4. override draw method to implement custom drawing based on drawableState (see getState method)
    5. in custom view override method that should draw drawable (for example setImageDrawable, setBackground... depends on your needs)
    6. in the method call supermethod with your custom Drawable class

    Example:

    public class CircularImageView extends ImageView{
    
        @Override
        public void setImageDrawable(Drawable drawable) {
            super.setImageDrawable(new CustomDrawable(
                ((BitmapDrawable)drawable).getBitmap()));
        }
    
        protected class CustomDrawable extends Drawable {
            // 
            private Bitmap bitmap;
    
            public CustomDrawable(Bitmap bitmap){
                this.bitmap = bitmap;
            }
    
            @Override
            public boolean isStateful() {
                // always return true
                return true;
            }
    
            @Override
            public int getOpacity() {
                // see documentation on android developers site
                return PixelFormat.OPAQUE;
            }
    
            @Override
            public void setColorFilter(ColorFilter colorFilter) {
            }
    
            @Override
            public void setAlpha(int i) {
            }
    
            boolean pressed = false;
    
            @Override
            protected boolean onStateChange(int[] states) {
                // simplified but working
                for (int state : getState()){
                    if (state == android.R.attr.state_pressed ||
                        state == android.R.attr.state_focused)
                            pressed = true;
                    else pressed = false;
                }
                invalidateSelf();
                return true;
            }
    
            @Override
            public void draw(Canvas canvas) {
                // very simplified example
                canvas.drawBitmap(bitmap,0,0,paint);
                circlePaint.setColor(pressed ? colorActive : colorPassive);
                canvas.drawCircle(0, 0, 100, 100);
            }
        }
    }