2011-07-14 40 views
1

我有一個問題:我不知道如何使我的layout可縮放。我發現了一些技巧來解決這個問題的ImageViewBitmapDrawable,或類似的東西,但不是layout。我想放置一個自定義視圖的數組(實際上只是一個矩形,我忽略了onDraw)。有沒有一些方法可以解決這個問題(我只是不想重複發明)或者我需要自己做所有事情?也許有人做過這樣的事情?我試圖用ScaleGestureDetector做一些事情,但失敗了。我的代碼如下所示製作可縮放的自定義佈局

public class Seat extends View { 

    private float mLastTouchX; 
    private float mLastTouchY; 

    private float mPosX; 
    private float mPosY; 
    private float mWidth; 
    private float mHeight; 

    private static final int INVALID_POINTER_ID = -1; 

    public static final int ACTION_POINTER_INDEX_MASK = 0xff00; 
    public static final int ACTION_POINTER_INDEX_SHIFT = 8; 

    // The ‘active pointer’ is the one currently moving our object. 
    private int mActivePointerId = INVALID_POINTER_ID; 

    private ScaleGestureDetector mScaleDetector; 
    private float mScaleFactor = 1.f; 

    private boolean checked = false; 
    private boolean reserved = false; 
    private Place place; 

    public Seat(PlacesActivity context, Place place) { 
     super(context); 
     setOnClickListener(new OnSeatClickListener(context)); 
     if (place.getReservation() != 1 || place.getStatus() != 1) { 
      reserved = true; 
     } 
     this.place = place; 
     this.mPosX = place.getX(); 
     this.mPosY = place.getY(); 

     mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) mWidth, (int) mHeight); 
     params.leftMargin = (int) mPosX; 
     params.topMargin = (int) mPosY; 
     setLayoutParams(params); 
     RelativeLayout parent = (RelativeLayout) getParent(); 

     Place place = (Place) getTag(); 
     for (int i = 0; i < parent.getChildCount(); i++) { 
      Seat seat = (Seat) parent.getChildAt(i); 
      Place placeToCompare = (Place) seat.getTag(); 
      if (place.getId() == placeToCompare.getId()) { 
       parent.removeViewAt(i); 
       parent.addView(this, i, params); 
      } 
     } 

     if (reserved) 
      canvas.drawColor(Color.GRAY); 
     else if (checked) 
      canvas.drawColor(Color.RED); 
     else 
      canvas.drawColor(Color.GREEN); 
    } 

    public void setChecked() { 
     checked = true; 
    } 

    public void setUnchecked() { 
     checked = false; 
    } 

    public boolean isChecked() { 
     return checked; 
    } 

    public void setReserved() { 
     reserved = true; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     // Let the ScaleGestureDetector inspect all events. 
     mScaleDetector.onTouchEvent(ev); 

     final int action = ev.getAction(); 
     switch (action & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: { 
       final float x = ev.getX(); 
       final float y = ev.getY(); 

       mLastTouchX = x; 
       mLastTouchY = y; 
       mActivePointerId = ev.getPointerId(0); 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: { 
       final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
       final float x = ev.getX(pointerIndex); 
       final float y = ev.getY(pointerIndex); 

       // Only move if the ScaleGestureDetector isn't processing a gesture. 
       if (!mScaleDetector.isInProgress()) { 
        final float dx = x - mLastTouchX; 
        final float dy = y - mLastTouchY; 

        mPosX += dx; 
        mPosY += dy; 
        mWidth *= mScaleFactor; 
        mHeight *= mScaleFactor; 

        invalidate(); 
       } 

       mLastTouchX = x; 
       mLastTouchY = y; 

       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_CANCEL: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_UP: { 
       final int pointerIndex = (ev.getAction() & ACTION_POINTER_INDEX_MASK) 
         >> ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = ev.getPointerId(pointerIndex); 
       if (pointerId == mActivePointerId) { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        mLastTouchX = ev.getX(newPointerIndex); 
        mLastTouchY = ev.getY(newPointerIndex); 
        mActivePointerId = ev.getPointerId(newPointerIndex); 
       } 
       break; 
      } 
     } 

     return true; 
    } 

    private class OnSeatClickListener implements OnClickListener { 

     private PlacesActivity context; 

     public OnSeatClickListener(PlacesActivity context) { 
      this.context = context; 
     } 

     @Override 
     public void onClick(View view) { 
      if (!reserved) { 
       Seat seat = (Seat) view; 
       seat.checked = !seat.checked; 
       view.invalidate(); 
       Place place = (Place) view.getTag(); 
       context.changeSeatState(place); 
       Toast toast = Toast.makeText(context, "Place " + place.getPlace() + " row " + place.getRow(), Toast.LENGTH_SHORT); 
       toast.setGravity(Gravity.CENTER, 0, 0); 
       toast.show(); 
      } 
     } 
    } 

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) { 
      mScaleFactor *= detector.getScaleFactor(); 

      // Don't let the object get too small or too large. 
      mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 2.0f)); 

      invalidate(); 
      return true; 
     } 
    } 
} 

這是一類的觀點,我的佈局,我想放大含有一些這方面的意見。我試圖申請ScaleGestureDetector,但也失敗了。

回答

0

我製作了自定義佈局......並且它的縮放比例正確......我也實現了滾動功能,但它並不那麼好...我正在研究它..在這裏,我爲您分享我的代碼。它會幫助你很多,如果你讓更好的滾動比我....然後讓我知道...

這裏是

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 = 2.0f; 

//Different Operation to be used 
    private final int NONE_OPERATION=0; 
    private final int DRAG_OPERATION=1; 
    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; 

boolean mdrag=false,mZoom=false; 

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); 
    } 


    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); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 

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

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

      Log.d("ZoomPrint", "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("ZoomPrint", "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_POINTER_UP: 
      Log.d("ZoomPrint", "Event: Action_Pointer_UP "); 
      mdrag=true; 

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

      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); 

     if(!mdrag) 
      invalidate(); 

    return true; 
    } 


    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     onTouchEvent(ev); 
     return super.onInterceptTouchEvent(ev); 
    // return true; 
    } 







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




    @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())) 
        ); 
      } 
     } 
    } 



    @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(); 
    } 



    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("ZoomPrint", "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("ZoomPrint", "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 
      if(mScaleFactor>1.0f) 
      { 
        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("ZoomPrint", "OnDoubleTapEvent"); 
      return false; 
     } 


     @Override 
     public boolean onSingleTapConfirmed(MotionEvent e) { 
     // Log.d("ZoomPrint", "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) { 

        int distX= (int) distanceX, distY =(int) distanceY; 

     //Log.d("Print"," X " + this.mClipBound.left +" Y " + this.mClipBound.right + " b "+ this.mClipBound.bottom + " g" + this.mClipBound.top) ; 

     Log.d("Print", "Scroll X " + distanceX + " Y " + distanceY);  

       if(this.mClipBound.left<=0) 
        this.scrollTo(-280, 0); 
       else if(this.mClipBound.top<=0) 
        this.scrollTo(0, -250); 
        else if (this.mClipBound.right>=1047) 
         this.scrollTo(280, 0); 
        else if (this.mClipBound.bottom>=800) 
         this.scrollTo(0, 250); 
        else 
        this.scrollBy((int)distanceX,(int)distanceY); 


        return true; 

      } 


     @Override 
     public void onShowPress(MotionEvent e) { 

     } 


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

評論中onScroll方法的代碼來獲取變焦性能。由於需求,滾動被硬編碼。我正在尋找正確的滾動方式,讓我們看看... – user1169079

+0

你是否找到了一些好方法 – pengwang