2017-04-11 98 views
0

我用this来执行捏缩放和拖动。Android - Pinch-zoomable Android的框架布局

public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener { 

    private enum Mode { 
    NONE, 
    DRAG, 
    ZOOM 
    } 

    private static final String TAG = "ZoomLayout"; 
    private static final float MIN_ZOOM = 1.0f; 
    private static final float MAX_ZOOM = 4.0f; 

    private Mode mode = Mode.NONE; 
    private float scale = 1.0f; 
    private float lastScaleFactor = 0f; 

    // Where the finger first touches the screen 
    private float startX = 0f; 
    private float startY = 0f; 

    // How much to translate the canvas 
    private float dx = 0f; 
    private float dy = 0f; 
    private float prevDx = 0f; 
    private float prevDy = 0f; 

    public ZoomLayout(Context context) { 
    super(context); 
    init(context); 
    } 

    public ZoomLayout(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(context); 
    } 

    public ZoomLayout(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(context); 
    } 

    private void init(Context context) { 
    final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this); 
    this.setOnTouchListener(new View.OnTouchListener() { 
     @Override 
     public boolean onTouch(View view, MotionEvent motionEvent) { 
     switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: 
      Log.i(TAG, "DOWN"); 
      if (scale > MIN_ZOOM) { 
       mode = Mode.DRAG; 
       startX = motionEvent.getX() - prevDx; 
       startY = motionEvent.getY() - prevDy; 
      } 
      break; 
      case MotionEvent.ACTION_MOVE: 
      if (mode == Mode.DRAG) { 
       dx = motionEvent.getX() - startX; 
       dy = motionEvent.getY() - startY; 
      } 
      break; 
      case MotionEvent.ACTION_POINTER_DOWN: 
      mode = Mode.ZOOM; 
      break; 
      case MotionEvent.ACTION_POINTER_UP: 
      mode = Mode.DRAG; 
      break; 
      case MotionEvent.ACTION_UP: 
      Log.i(TAG, "UP"); 
      mode = Mode.NONE; 
      prevDx = dx; 
      prevDy = dy; 
      break; 
     } 
     scaleDetector.onTouchEvent(motionEvent); 

     if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) { 
      getParent().requestDisallowInterceptTouchEvent(true); 
      float maxDx = (child().getWidth() - (child().getWidth()/scale))/2 * scale; 
      float maxDy = (child().getHeight() - (child().getHeight()/scale))/ 2 * scale; 
      dx = Math.min(Math.max(dx, -maxDx), maxDx); 
      dy = Math.min(Math.max(dy, -maxDy), maxDy); 
      Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx 
      + ", max " + maxDx); 
      applyScaleAndTranslation(); 
     } 

     return true; 
     } 
    }); 
    } 

    // ScaleGestureDetector 

    @Override 
    public boolean onScaleBegin(ScaleGestureDetector scaleDetector) { 
    Log.i(TAG, "onScaleBegin"); 
    return true; 
    } 

    @Override 
    public boolean onScale(ScaleGestureDetector scaleDetector) { 
    float scaleFactor = scaleDetector.getScaleFactor(); 
    Log.i(TAG, "onScale" + scaleFactor); 
    if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) { 
     scale *= scaleFactor; 
     scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM)); 
     lastScaleFactor = scaleFactor; 
    } else { 
     lastScaleFactor = 0; 
    } 
    return true; 
    } 

    @Override 
    public void onScaleEnd(ScaleGestureDetector scaleDetector) { 
    Log.i(TAG, "onScaleEnd"); 
    } 

    private void applyScaleAndTranslation() { 
    child().setScaleX(scale); 
    child().setScaleY(scale); 
    child().setTranslationX(dx); 
    child().setTranslationY(dy); 
    } 

    private View child() { 
    return getChildAt(0); 
    } 
} 

我遇到的问题是,当我放大,然后拖动,它会捕捉到屏幕中间。我认为问题在于:

case MotionEvent.ACTION_DOWN: 
      Log.i(TAG, "DOWN"); 
      if (scale > MIN_ZOOM) { 
       mode = Mode.DRAG; 
       startX = motionEvent.getX() - prevDx; 
       startY = motionEvent.getY() - prevDy; 
      } 
      break; 

我不知道如何解决这个问题,任何人都可以帮我吗?

+0

你为什么不使用'GestureDetector'和'ScaleGestureDetector'? – pskink

+0

@pskink感谢您的贡献,但我已修复它。 – Brooks

回答

0

我固定它通过改变onScale到:

public boolean onScale(ScaleGestureDetector scaleDetector) { 
     float scaleFactor = scaleDetector.getScaleFactor(); 
     Log.i(TAG, "mode:" + this.mode + ", onScale:" + scaleFactor); 
     if (this.lastScaleFactor == 0.0f || Math.signum(scaleFactor) == Math.signum(this.lastScaleFactor)) { 
      this.scale *= scaleFactor; 
      this.scale = Math.max(MIN_ZOOM, Math.min(this.scale, MAX_ZOOM)); 
      this.lastScaleFactor = scaleFactor; 
     } else { 
      this.lastScaleFactor = 0.0f; 
     } 
     if (this.mSurfaceView != null) { 
      int orgWidth = getWidth(); 
      int _width = (int) (((float) orgWidth) * this.scale); 
      int _height = (int) (((float) getHeight()) * this.scale); 
      LogUtil.b(new StringBuilder(String.valueOf(_width)).append(", ").append(_height).toString()); 
      LayoutParams params = (LayoutParams) this.mSurfaceView.getLayoutParams(); 
      params.height = _height; 
      params.width = _width; 
      this.mSurfaceView.setLayoutParams(params); 
      child().setScaleX(this.scale); 
      child().setScaleY(this.scale); 
     } 
     return true; 
    } 
+0

'mSurfaceView'未定义。 – Tijmen