2012-04-21 5 views
1

나는 Android에 익숙하지 않아서 많은 연구를 통해 확대/축소를위한 사용자 지정 상대 레이아웃을 만들었으며 지금은 Imageview, 즉 바운드 제한처럼 작동해야하는 패닝/드래그를 통합하려고합니다. .스크롤/패닝 또는 사용자 정의 레이아웃에서 드래그

매트릭스를 사용하지 않고 ScaleGestureDetector.SimpleOnScaleGestureListener입니다. 이제는 동일한 패닝/드래깅을 통합하려고합니다.

내 코드에서 드래그/패닝을 수행하려면 어떻게해야합니까? 적절한 코멘트와 이해력을 가진 내 맞춤 상대 레이아웃입니다.

/* 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
* 
* @description : Custom Layout Zoom 
* 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
*/ 

package com.layoutzooming; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Rect; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.GestureDetector; 
import android.view.GestureDetector.OnDoubleTapListener; 
import android.view.GestureDetector.OnGestureListener; 
import android.view.MotionEvent; 
import android.view.ScaleGestureDetector; 
import android.view.View; 
import android.view.ViewParent; 
import android.widget.RelativeLayout; 

public class ZoomLayout extends RelativeLayout implements OnDoubleTapListener, OnGestureListener{ 

    //ScalingFactor i.e. Amount of Zoom 
    static float mScaleFactor = 1.0f; 

    // Maximum and Minimum Zoom 
    private static float MIN_ZOOM = 1.0f; 
    private static float MAX_ZOOM = 3.0f; 

    //Different Operation to be used 
    private final int NONE_OPERATION=0; 
    private final int ZOOM_OPERATION=2; 
    private float mWidth= 1280; 
    private float mHeight=800; 

    // Mode to select the operation 
    private int mode; 

    //Track X and Y coordinate of the finger when it first touches the screen 
    private float mInitialX = 0f; 
    private float mInitialY = 0f; 

    // Track the Bound of the Image after zoom to calculate the offset 
    static Rect mClipBound; 

    // mDetector to detect the scaleGesture for the pinch Zoom 
    private ScaleGestureDetector mDetector; 

    // mDoubleTapDetector to detect the double tap 
    private GestureDetector mDoubleTapDetector; 

    //Pivot point for Scaling 
    static float gx=0,gy=0; 


    /* 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @description : Constructor is called when used via XML 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 

    public ZoomLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     setWillNotDraw(false); 
     mClipBound = new Rect(); 
     // Intialize ScaleGestureDetector 
     mDetector = new ScaleGestureDetector(getContext(), new ZoomListener()); 
     mDoubleTapDetector = new GestureDetector(context,this); 
     mDoubleTapDetector.setOnDoubleTapListener(this); 
    } 

    /* 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @description : Constructor is called when used via code 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    public ZoomLayout(Context context) { 
     super(context); 
     setWillNotDraw(false); 
     mClipBound = new Rect(); 
     // Intialize ScaleGestureDetector 
     mDetector = new ScaleGestureDetector(getContext(), new ZoomListener()); 
     mDoubleTapDetector = new GestureDetector(context,this); 
     mDoubleTapDetector.setOnDoubleTapListener(this); 
    } 

    /* 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @description : OnTouchEvent of the layout which handles all type of motion-events possible 
    * @ Returns : true - we are handling the touchEvent. 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 

     // Handles all type of motion-events possible 
     switch(event.getAction() & MotionEvent.ACTION_MASK) { 

      case MotionEvent.ACTION_DOWN: 
       // Event occurs when the first finger is pressed on the Screen 

       Log.d("Print", "Event: Action_Down "); 
       mInitialX = event.getX(); 
       mInitialY = event.getY(); 

       break; 

      case MotionEvent.ACTION_POINTER_DOWN: 
       //Event occurs when the second finger is pressed down 

       Log.d("Print", "Event: Action_Pointer_Down "); 
       // If second finger is pressed on the screen with the first set the Mode to Zoom operation 
       mode=ZOOM_OPERATION; 

       break; 

      case MotionEvent.ACTION_UP: 
       //Event occurs when all the finger are taken of the screen 
       Log.d("Print", "Event: Action_UP "); 
       //If all the fingers are taken up there will be no operation 
       mode = NONE_OPERATION; 


       break; 
     } 

     // Give the event to the mDetector to get the scaling Factor 
     mDetector.onTouchEvent(event); 

     // Give the event to the mDoubleTapDetector for the doubleTap 
     mDoubleTapDetector.onTouchEvent(event); 

     return true; 
    } 

    /* 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @description : By overriding the onInterceptTouchEvent y overriding the onInterceptTouchEvent, 
    * This allows you to watch events as they are dispatched to your children, and 
    * take ownership of the current gesture at any point. Allowing onTouchEvent of RelativeLayout to handle the 
    * all the motioin events . 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     onTouchEvent(ev); 
     return super.onInterceptTouchEvent(ev); 

    } 

    /* 
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @descriptiont : invalidateChildInParent 
    * 
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    @Override 
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) { 
     return super.invalidateChildInParent(location, dirty); 
    } 

    /* 
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @descriptiont : Correctly sets the x,y position of the children relative to each other for different scale factors. 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) 
    { 
     int count = getChildCount(); 
     for(int i=0;i<count;i++){ 
      View child = getChildAt(i); 
      if(child.getVisibility()!=GONE){ 
       RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams(); 
       child.layout(
        (int)(params.leftMargin), 
        (int)(params.topMargin), 
        (int)((params.leftMargin + child.getMeasuredWidth())), 
        (int)((params.topMargin + child.getMeasuredHeight())) 
        ); 
      } 
     } 
    } 

    /* 
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @description : Called by draw to draw the ChildViews. We need to gained control before the children are 
    * drawn so that to apply the scaling Factors 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    @Override 
    protected void dispatchDraw(Canvas canvas) { 

     //Save the canvas to set the scaling factor returned from detector 
     canvas.save(Canvas.MATRIX_SAVE_FLAG); 

     canvas.scale(mScaleFactor, mScaleFactor,gx,gy); 

     super.dispatchDraw(canvas); 

     mClipBound = canvas.getClipBounds(); 

      canvas.restore(); 
    } 

    /* 
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    * 
    * @name : ZoomListener 
    * @description : Class which defines the listener for ScaleGestureDetector 
    * 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
    */ 
    private class ZoomListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      // getting the scaleFactor from the detector 
      mScaleFactor *= detector.getScaleFactor(); // Gives the scaling factor from the previous scaling to the current 
      // Log.d("Print", "detector scaling Factor" + mScaleFactor); 

      gx = detector.getFocusX(); 
      gy = detector.getFocusY(); 
      // Limit the scale factor in the MIN and MAX bound 
      mScaleFactor= Math.max(Math.min(mScaleFactor, MAX_ZOOM),MIN_ZOOM); 
      // Log.d("Print", "Bounded scaling Factor" + mScaleFactor); 

      /*//Force canvas to redraw itself only if the one event is to happen (say Zooming only) else do not invalidate here for multi operations 
       As what we de for scrolling or panning will not reflect here. So we will add this in onDraw method 
      invalidate();*/ 
      // Here we are only zooming so invalidate has to be done 
      invalidate(); 
      requestLayout(); 

      // we have handle the onScale 
      return true; 
     } 
    } 

    @Override 
    public boolean onDoubleTap(MotionEvent e) { 
     // Make the mScaleFactor to its normal value 
     mScaleFactor=1.0f; 
     // Force the canvas to redraw itself again as the changes has been occured. 
     invalidate(); 
     requestLayout(); 
      return false; 
    } 

    @Override 
    public boolean onDoubleTapEvent(MotionEvent e) { 
     // Log.d("Print", "OnDoubleTapEvent"); 
      return false; 
    } 

    @Override 
    public boolean onSingleTapConfirmed(MotionEvent e) { 
     // Log.d("Print", "OnSingleTap"); 
      return false; 
    } 

    @Override 
    public boolean onDown(MotionEvent e) { 
     // TODO Auto-generated method stub 
     return false; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, 
          float velocityX, float velocityY) { 
     return false; 
    } 


    @Override 
    public void onLongPress(MotionEvent e) { 
    } 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, 
          float distanceX, float distanceY) { 
     return false; 
    } 

    @Override 
    public void onShowPress(MotionEvent e) { 

    } 

    @Override 
    public boolean onSingleTapUp(MotionEvent e) { 
     return false; 
    } 
} 
+0

일반 ScrollView 내부에서 HorizontalScrollView를 사용하여 모든 방향으로 스크롤/패닝 할 수 있습니까? – Kostas

+0

@ Kostas : 모든 방향으로 활성화하는 방법은 없습니까 ?? – user1169079

+0

ScrollView 안에 HorizontalScrollView를 두어 어떻게 작동하는지보십시오 :-) – Kostas

답변

2

나는 똑같이하고있다. onTouchEvent ACTION_UP 이벤트에 다음을 추가했습니다. mScaleFactor, mInitialX, mInitialY가 ScaleGestureDetector onScale 함수 출신

  if (mScaleFactor > 1) 
      { 
       gx = gx - (event.getX() - mInitialX); 
       gy = gy - (event.getY() - mInitialY); 
       invalidate(); 
       requestLayout(); 
      } 

. 크기 조정이 잘 작동합니다. 레이아웃에서 뷰를 선택할 수는 없지만 크기가 조정되면 때때로 그것은 작동하고 때로는 그렇지 않습니다.