Multistate ImageView in Android

As per Android design guidelines every interactive element in layout has to have a touch feedback and so do image views.

Since my app has complicated UI with multiple imageviews, I’ve dealt this with a custom imageview overriding onTouchEvent method to intercept touch events.

Trick is to apply ColorFilter on ACTION_DOWN and clear it on ACTION_UP or ACTION_CANCEL events. (make sure you return true in onTouchEvent or actions may get delegated to click action and ACTION_UP may never get called)

To handle onclick listener actions, calculate touch event duration and distance from initial touch coordinates on ACTIONUP event and invoke performClick() accordingly.

Here is the code snippet for reference:

 private static final int MAX_CLICK_DISTANCE = 15;  
      private long pressStartTime;  
      private float pressedX;  
      private float pressedY;  
      private static final int MAX_CLICK_DURATION = 500;  
      @Override  
      public boolean onTouchEvent(MotionEvent event) {  
           if (null == getDrawable())  
                return super.onTouchEvent(event);  
           switch (event.getAction()) {  
           case MotionEvent.ACTION_DOWN: {  
                pressStartTime = System.currentTimeMillis();  
                pressedX = event.getX();  
                pressedY = event.getY();  
                // overlay is white with transparency of 0x40 (25)  
                getDrawable().setColorFilter(0x40ffffff, PorterDuff.Mode.SRC_ATOP);  
                invalidate();  
                break;  
           }  
           case MotionEvent.ACTION_UP:  
                long pressDuration = System.currentTimeMillis() - pressStartTime;  
                if (pressDuration < MAX_CLICK_DURATION  
                          && distance(pressedX, pressedY, event.getX(), event.getY()) < MAX_CLICK_DISTANCE) {  
                     performClick();  
                }  
           case MotionEvent.ACTION_CANCEL: {  
                // clear the overlay  
                getDrawable().clearColorFilter();  
                invalidate();  
                break;  
           }  
           }  
           return true;  
      }  
      private static float distance(float x1, float y1, float x2, float y2) {  
           float dx = x1 - x2;  
           float dy = y1 - y2;  
           float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);  
           return pxToDp(distanceInPx);  
      }  
      private static float density;  
      private static float pxToDp(float px) {  
           return px / density;  
      }  

Above code looks for minimum touch duration of 500ms and maximum movement of 15dp to perform click actions.

Visual feedback looks like:

combine_images1

Here is the demo project on github with custom imageview to support pressed state changes.

Hope this helps.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s