VizGhar
VizGhar

Reputation: 3128

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?

Upvotes: 3

Views: 3463

Answers (2)

VizGhar
VizGhar

Reputation: 3128

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);
        }
    }
}

Upvotes: 3

adboco
adboco

Reputation: 2870

Create a boolean to control when the view is pressed and override onTouchEvent to set it true or false:

private boolean pressed;

@Override
protected void onDraw(Canvas canvas) {
    // ...
    if (pressed){
        // code when pressed
    }
    else{
        // otherwise
    }
}

@Override
public boolean onTouchEvent(MotionEvent event){
    switch(event.getAction()){
        case MotionEvent.ACTION_DOWN:
            pressed = true;
            this.invalidate();
            break;
        case MotionEvent.ACTION_UP:
            pressed = false;
            this.invalidate();
            break;
     }
}

Upvotes: 2

Related Questions