1

I have a custom View, which overrides onDraw and basically draws a custom shape with canvas. I would like to change the color, when the view is touched.

Looking around StackOverflow, it seems like the preferred way for Buttons is to set up a drawable selector list with various colors set on android:state_pressed and android:state_focused. However, that approach does not seem to work for me, as I am drawing the shape myself, and the color is set on my own Paint object.

Here's what I have now:

I set up custom attributes as such with a simple color attribute:

<declare-styleable name="CustomView">

  <attr name="color" format="color"/>

</declare-styleable>

I retrieve the color in CustomView's constructor, and setup a Paint:

private final Paint paint;

...

TypedArray conf = context.obtainStyledAttributes(
  attributes,
  R.styleable.CustomView
);
Resources resources = getResources();
int color = conf.getColor(
  R.styleable.CustomView_color,
  resources.getColor(R.color.blue)
);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);

Finally, I use it in onDraw:

canvas.drawPath(shapePath, paint);

I started looking into a ColorStateList, but I am unclear on how I would integrate it into my code. Any suggestions on how to achieve the selector list functionality for my custom view would be much appreciated!

Community
  • 1
  • 1
Sanketh Katta
  • 5,961
  • 2
  • 29
  • 30

1 Answers1

1

Well, the easiest way to do it would be to change Paint object's color in on touch method of your custom view.

You could do it more less like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            paint.setColor(mPressedColor);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            paint.setColor(mNormalColor);
            invalidate();
            break;
    }
    return super.onTouchEvent(event);
}

(where mPressedColor and mNormalColor store int values for pressed and normal colors - respectively)

Bartek Lipinski
  • 30,698
  • 10
  • 94
  • 132
  • thanks! seems to work pretty well. but, why would I need to remove the `final` keyword? I'm not reassigning the `Paint` object anywhere (works fine with `final`). – Sanketh Katta Jan 02 '15 at 04:04
  • true that. at first I was thinking of a bit different approach (in which doing so was necessary). Let me edit my answer a bit then – Bartek Lipinski Jan 02 '15 at 04:06
  • also, remember that you might need to call `invalidate` to force redrawing (if no other changes can force it) – Bartek Lipinski Jan 02 '15 at 04:08
  • yup, I had to add that in my code, after each of the `setColor` calls – Sanketh Katta Jan 02 '15 at 04:09
  • exactly what I was thinking about:) – Bartek Lipinski Jan 02 '15 at 04:11
  • also, would it be correct to `return super.onTouchEvent(event);` here? or should it just always `return true;` if I am handling the event? – Sanketh Katta Jan 02 '15 at 04:26
  • Remember that you return `true` in `onTouchEvent` when you want to receive further motion events in this, lets say "motion event sequence". And that might not be the case. I set it up to `super.onTouchEvent(event)` cause I wanted this decision to be handled by View's onTouchEvent handler itself or any other onTouchListener that you or some1 else using your custom view might use. – Bartek Lipinski Jan 02 '15 at 04:29