Sunday, November 9, 2014

Pinch In/Out handling in android

Hi everyone,
Today, I would explain a use case of multiple touch handling that is "Pinch Out" and "Pinch In" on particular layout. Before I go ahead, I would like to explain what does it means when I say "Pinch In" and "Pinch Out".
In picture above, first image is the example of "Pinch In" where both the fingers are coming inside. While second image is example of "Pinch Out" in which both the fingers are going away.

You can achieve it either by using GestureDetector or ScaleGestureDetector Classes, both are designed to receive motion events.

In my opinion, to implement this particular use case of "Pinch In" and "Pinch Out", use of ScaleGestureDetector is convenient.

There we go...

Step 1: Declare ScaleGestureDetector class that will implement SimpleOnScaleGestureListener interface. The interface allows to override three methods onScale(), onScaleBegin() and onScaleEnd().
 @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.es_activity);  
     layout = (FrameLayout)  findViewById(R.id.chart);
     pinchIOGestureDetector =  
         new ScaleGestureDetector(this,  
             new PinchIOGestureListener());  
   }  

In code above, pinchIOGestureDetector is object of ScaleGestureDetector class that I have declared globally. 

Step 2:  Now, we have to define the Classes PinchIOGestureListener we have declared and override the methods provided by interface SimpleOnScaleGestureListener.

 public class PinchIOGestureListener extends
      SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor = detector.getScaleFactor();         
            return true;
        }
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }
        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
         if(scaleFactor > 1) {
           // Handle Pinch Out 
           } else {
           // Handle Pinch In 
          }
        }
    }

In second code snippet, I have global variable scaleFactor, that gets the scale factor from onScale method, Therefore, if scale factor would be more then 1, it means at the time of release of fingers the distance has increased while reverse for Pinch In.

Step 3: Now, in last step we need to apply this onTouchEvent on needed layout which in return will call onTouchEvent() method of the ScaleGestureDetector class.

layout.setOnTouchListener(new View.OnTouchListener() {  
       @Override  
       public boolean onTouch(View view, MotionEvent ev) {  
        // Log.d(TAG, "COUNT CHECK"+ev.getPointerCount());  
         if(ev.getPointerCount() > 1) {  
           pinchIOGestureDetector.onTouchEvent(ev);  
           return true;  
         }  else {  
           Log.d(TAG, "Single Touch hanlder");  
         }  
         return true;  
       }  
     });

As explained, I am just setting setOnTouchListener on FrameLayout Object.

This is it, I guess

* always return true from OnTouch otherwise it will move to next action.

P.S. This is my first blog post almost after 4 years so it might contains some silly mistakes.