title: How do I implement the zoom-in-zoom-out SMOOTHLY in Android? Relevant to SurfaceView with RTMP streaming
body: <p>I am implementing a feature that can zoom in or zoom out when playing RTMP streaming with SurfaceView object. I have done some research and I decided to calculate the size and the position first and use the onMeasure() method to re-build the view. </p>
  
  <p>Now I have a problem that the object doesn't really follow the position I set during zooming. The effect I would like to implement is like this <strong><a href="http://youtu.be/iRKer1AUfd0" rel="nofollow">video</a></strong> (which shows the behaviour of the iOS version of my app), and I recorded <strong><a href="http://www.youtube.com/watch?v=r1DYqMuf-9M" rel="nofollow">another video</a></strong> to show what I have done so far. The object would shift more frequently if I use the same position as the iOS version app. It is not smooth at all and might cause a poor user experience. </p>
  
  <p>My observation to the behaviour is that the object of SurfaceView would re-size its width and height with fixed position x and y as the zoom function triggered. Then, the object would shift backward which might result from following the layout of its parent. I printed log messages out and found that the position x and y would have been changed when onMeasure() was triggered. Although I have set the position in the function, it would still be changed when the process went to onLayout(). Since onLayout() is called as soon as the onMeasure() finished, so I don't see any possible timing to set the position to avoid the shifting.</p>
  
  <p>The following is what I have done:
  Layout:</p>
  
  <pre><code>&lt;RelativeLayout
      android:id="@+id/RelaytiveView"
      android:layout_width="fill_parent"
      android:layout_height="200dp"&gt;
      &lt;LinearLayout
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:layout_centerInParent="true"
          android:background="#000000"
          android:gravity="center"
          android:orientation="vertical" &gt;
          &lt;com.player.adapter.RtmpLiveSurfaceview
              android:id="@+id/goLiveView"
              android:layout_width="match_parent"
              android:layout_height="match_parent" /&gt;
      &lt;/LinearLayout&gt;
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p>And the code:</p>
  
  <pre><code>public class RtmpLiveSurfaceview extends SurfaceView 
  {
      private static final int DEFAULT_PIXEL_WIDTH = 1280;
      private static final int DEFAULT_PIXEL_HEIGHT = 720;
      private float INIT_WIDTH;
      private float INIT_HEIGHT;
      private float WIDTH = 0;
      private float HEIGHT = 0;
      private float SCALER = (float) 1.0;
      private float TAG_POINT_X = 0;
      private float TAG_POINT_Y = 0;
  
      private float INIT_DIST = 0;
      SurfaceHolder mholder;
  
      static final int ZOOM = 2;
  
      @Override
      protected void onSizeChanged (int w, int h, int oldw, int oldh)
      {
      }
      @Override
      protected void onLayout (boolean changed, int left, int top, int right, int bottom)
      {
          setX(TAG_POINT_X);
          setY(TAG_POINT_Y);
      }
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
      {
          int width = getDefaultSize(DEFAULT_PIXEL_WIDTH, widthMeasureSpec);
          int height = getDefaultSize(DEFAULT_PIXEL_HEIGHT, heightMeasureSpec);
          if (DEFAULT_PIXEL_WIDTH &gt; 0 &amp;&amp; DEFAULT_PIXEL_HEIGHT &gt; 0)
          {
              if ( DEFAULT_PIXEL_WIDTH * height  &gt; width * DEFAULT_PIXEL_HEIGHT )
              {
                  height = width * DEFAULT_PIXEL_HEIGHT / DEFAULT_PIXEL_WIDTH;
              } 
              else if ( DEFAULT_PIXEL_WIDTH * height  &lt; width * DEFAULT_PIXEL_HEIGHT )
              {
                  width = height * DEFAULT_PIXEL_WIDTH / DEFAULT_PIXEL_HEIGHT;
              }
              else
              {
              }
          }
          INIT_WIDTH = width;
          INIT_HEIGHT = height;
          if(WIDTH == 0)
          {
              WIDTH = INIT_WIDTH;
              HEIGHT = INIT_HEIGHT;
          }
          int wmode = MeasureSpec.getMode(widthMeasureSpec);
          int hmode = MeasureSpec.getMode(heightMeasureSpec);
          int widthSpec = MeasureSpec.makeMeasureSpec((int)WIDTH, wmode);
          int heightSpec = MeasureSpec.makeMeasureSpec((int)HEIGHT, hmode);
          setX(TAG_POINT_X);
          setY(TAG_POINT_Y);
          super.onMeasure(widthSpec, heightSpec);
      }
      public void init() 
      {
          mholder = getHolder();
          mholder.setSizeFromLayout();
          mholder.addCallback(new Callback() 
          {
              @Override
              public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
              {
              }
          });
      }
  
      public boolean onTouchEvent(MotionEvent MEvent) 
      {
          switch (MEvent.getAction() &amp; MotionEvent.ACTION_MASK) 
          {
              case MotionEvent.ACTION_POINTER_DOWN:
              {
                  if(MEvent.getPointerCount() &gt;= 2)
                  {
                      mode = ZOOM;
                      INIT_DIST = spacing(MEvent);
                      break;
                  }
              }
              case MotionEvent.ACTION_MOVE:
              {
                  if (mode == ZOOM) 
                  {
                      if(MEvent.getPointerCount() &gt;= 2)
                      {
                          float newDist = spacing(MEvent);
                          float tmp_scaler = (float) (((newDist - INIT_DIST) * 0.1 + INIT_DIST) / INIT_DIST);
                          if((tmp_scaler * WIDTH) &gt; (2.0 * INIT_WIDTH))
                              tmp_scaler = (float) (((newDist - INIT_DIST) * 0.01 + INIT_DIST) / INIT_DIST);
                          WIDTH = getWidth();
                          HEIGHT = getHeight();
                          if (((tmp_scaler * WIDTH) &gt;= (1.0 * INIT_WIDTH)) &amp;&amp; ((tmp_scaler * WIDTH) &lt;= (4.0 * INIT_WIDTH)))
                          {
                              SCALER = tmp_scaler;
                              TAG_POINT_X = getX();
                              if((TAG_POINT_X + WIDTH * SCALER) &lt; INIT_WIDTH)
                                  TAG_POINT_X = INIT_WIDTH - WIDTH * SCALER;
                              else if(TAG_POINT_X &gt; 0)
                                  TAG_POINT_X = 0;
                              TAG_POINT_Y = getY();
                              if((TAG_POINT_Y + HEIGHT * SCALER) &lt; INIT_HEIGHT)
                                  TAG_POINT_Y = INIT_HEIGHT - HEIGHT * SCALER;
                              else if(TAG_POINT_Y &gt; 0)
                                  TAG_POINT_Y = 0;
                              WIDTH = WIDTH * SCALER;
                              HEIGHT = HEIGHT * SCALER;
                              requestLayout();
                          }
                      }
                  }
                  break;
              }
  
          }
  
          return true;
      }
  }
  </code></pre>
  
  <p>Can anyone help me? If it is not possible to implement zoom-in-zoom-out function with SurfaceView, is there any suggested solution? Thanks.</p>