7

Tôi đã tạo một chế độ xem có thể kéo bên trong RelativeLayout. Nhưng dường như nó vượt ra ngoài RelativeLayout.Giới hạn Chế độ xem để kéo bên trong RelativeLayout

tôi chỉ đơn giản muốn thực hiện một Xem kéo bên ViewGroup

Và quan điểm này là draggable theo màn hình. Và nó có thể kéo được vượt ra ngoài ranh giới của RelativeLayout. Làm thế nào tôi có thể hạn chế nó ở lại kéo được trong RelativeLayout.

CustomImageButton

public class ImageButtonCustom extends ImageButton implements View.OnTouchListener{ 

    float dX, dY; 

    private RelativeLayout rootView; 
    private ImageButtonCustom imageButtonCustom; 
    private OnMoveListener onMoveListener; 

    public ImageButtonCustom(Context context,RelativeLayout rootView){ 
     super(context); 
     this.rootView = rootView; 
     init(); 

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

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

    public ImageButtonCustom(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(); 
    } 

    private void init(){ 
     imageButtonCustom = this; 
     setImageResource(R.drawable.upper_left); 
     setBackgroundColor(Color.TRANSPARENT); 
     setOnTouchListener(this); 

     /*RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); 
     rl.addRule(RelativeLayout.ALIGN_BOTTOM);*/ 

     rootView.addView(this); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     switch (event.getAction() & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: 
       dX = v.getX() - event.getRawX(); 
       dY = v.getY() - event.getRawY(); 
       break; 
      case MotionEvent.ACTION_UP: 
       break; 
      case MotionEvent.ACTION_POINTER_DOWN: 
       break; 
      case MotionEvent.ACTION_POINTER_UP: 
       break; 
      case MotionEvent.ACTION_MOVE: 
       v.animate() 
         .x(event.getRawX() + dX) 
         .y(event.getRawY() + dY) 
         .setDuration(0) 
         .start(); 
       //no use of ViewPositionUtil 
       onMoveListener.onMove(new Position());//positionXY); 
       break; 
     } 
     rootView.invalidate(); 
     return true; 
    } 

    public void setOnMoveListener(OnMoveListener onMoveListener){ 
     this.onMoveListener = onMoveListener; 
    } 

    public float getCenterX(){ 
     return getX() + getWidth()/2; 

    } 
    public float getCenterY(){ 
     return getY() + getHeight()/2; 

    } 

    public interface OnMoveListener{ 
     void onMove(Position positionXY); 
    } 
} 

EDIT:

Các ImageButton là Draggable nhưng nó đi outside of parent. Giới hạn để kéo trong Bố cục cha mẹ của nó.

+0

cũng đã cố gắng http://stackoverflow.com/ câu hỏi/21662397/cách giữ-an-hình ảnh-trong-bố cục-với-kéo-và-thả – Nepster

Trả lời

9

Đây là trích xuất từ ​​nhật ký cũ của tôi. Hi vọng nó sẽ giúp ích cho bạn.

public class OnDragTouchListener implements View.OnTouchListener { 

    /** 
    * Callback used to indicate when the drag is finished 
    */ 
    public interface OnDragActionListener { 
     /** 
     * Called when drag event is started 
     * 
     * @param view The view dragged 
     */ 
     void onDragStart(View view); 

     /** 
     * Called when drag event is completed 
     * 
     * @param view The view dragged 
     */ 
     void onDragEnd(View view); 
    } 

    private View mView; 
    private View mParent; 
    private boolean isDragging; 
    private boolean isInitialized = false; 

    private int width; 
    private float xWhenAttached; 
    private float maxLeft; 
    private float maxRight; 
    private float dX; 

    private int height; 
    private float yWhenAttached; 
    private float maxTop; 
    private float maxBottom; 
    private float dY; 

    private OnDragActionListener mOnDragActionListener; 

    public OnDragTouchListener(View view) { 
     this(view, (View) view.getParent(), null); 
    } 

    public OnDragTouchListener(View view, View parent) { 
     this(view, parent, null); 
    } 

    public OnDragTouchListener(View view, OnDragActionListener onDragActionListener) { 
     this(view, (View) view.getParent(), onDragActionListener); 
    } 

    public OnDragTouchListener(View view, View parent, OnDragActionListener onDragActionListener) { 
     initListener(view, parent); 
     setOnDragActionListener(onDragActionListener); 
    } 

    public void setOnDragActionListener(OnDragActionListener onDragActionListener) { 
     mOnDragActionListener = onDragActionListener; 
    } 

    public void initListener(View view, View parent) { 
     mView = view; 
     mParent = parent; 
     isDragging = false; 
     isInitialized = false; 
    } 

    public void updateBounds() { 
     updateViewBounds(); 
     updateParentBounds(); 
     isInitialized = true; 
    } 

    public void updateViewBounds() { 
     width = mView.getWidth(); 
     xWhenAttached = mView.getX(); 
     dX = 0; 

     height = mView.getHeight(); 
     yWhenAttached = mView.getY(); 
     dY = 0; 
    } 

    public void updateParentBounds() { 
     maxLeft = 0; 
     maxRight = maxLeft + mParent.getWidth(); 

     maxTop = 0; 
     maxBottom = maxTop + mParent.getHeight(); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     if (isDragging) { 
      float[] bounds = new float[4]; 
      // LEFT 
      bounds[0] = event.getRawX() + dX; 
      if (bounds[0] < maxLeft) { 
       bounds[0] = maxLeft; 
      } 
      // RIGHT 
      bounds[2] = bounds[0] + width; 
      if (bounds[2] > maxRight) { 
       bounds[2] = maxRight; 
       bounds[0] = bounds[2] - width; 
      } 
      // TOP 
      bounds[1] = event.getRawY() + dY; 
      if (bounds[1] < maxTop) { 
       bounds[1] = maxTop; 
      } 
      // BOTTOM 
      bounds[3] = bounds[1] + height; 
      if (bounds[3] > maxBottom) { 
       bounds[3] = maxBottom; 
       bounds[1] = bounds[3] - height; 
      } 

      switch (event.getAction()) { 
       case MotionEvent.ACTION_CANCEL: 
       case MotionEvent.ACTION_UP: 
        onDragFinish(); 
        break; 
       case MotionEvent.ACTION_MOVE: 
        mView.animate().x(bounds[0]).y(bounds[1]).setDuration(0).start(); 
        break; 
      } 
      return true; 
     } else { 
      switch (event.getAction()) { 
       case MotionEvent.ACTION_DOWN: 
        isDragging = true; 
        if (!isInitialized) { 
         updateBounds(); 
        } 
        dX = v.getX() - event.getRawX(); 
        dY = v.getY() - event.getRawY(); 
        if (mOnDragActionListener != null) { 
         mOnDragActionListener.onDragStart(mView); 
        } 
        return true; 
      } 
     } 
     return false; 
    } 

    private void onDragFinish() { 
     if (mOnDragActionListener != null) { 
      mOnDragActionListener.onDragEnd(mView); 
     } 

     dX = 0; 
     dY = 0; 
     isDragging = false; 
    } 
} 

Và bạn có thể đặt nó bằng cách sử:

myView.setOnTouchListener(new OnDragTouchListener(myView)); 

Hoặc bằng cách thêm phương pháp này trực tiếp trong init của Custom View của bạn:

setOnTouchListener(new OnDragTouchListener(this)); 
+0

myView.setOnTouchListener (new OnDragTouchListener (myView, myParentView)); wroks cảm ơn – Nepster

+0

Tuyệt vời! cảm ơn người đàn ông! – belphegor

+0

Xin chào đoạn trích đẹp ... Cách thêm onClickListener vào cùng một chế độ xem với cùng chức năng? – AndiM

1

Trong OnTouch bạn tính toán nơi để di chuyển tầm nhìn của bạn

case MotionEvent.ACTION_MOVE: 
      v.animate() 
        .x(event.getRawX() + dX) 
        .y(event.getRawY() + dY) 
        .setDuration(0) 
        .start(); 

Bạn nên kiểm tra ranh giới cho x và y trước khi chuyển nó.

case MotionEvent.ACTION_MOVE: 
     float x = event.getRawX() + dX; float y = event.getRawY() + dY; 
     if (x > boundaryRight) x = boundaryRight; 
     else if (x < boundaryLeft) x = boundaryLeft; 
     if (y < boundaryTop) y = boundaryTop; 
     else if (y > boundaryBottom) y = boundaryBottom; 
     v.animate() 
       .x(x) 
       .y(y) 
       .setDuration(0) 
       .start(); 

Và để tính toán ranh giới của RelativeLayout của bạn tại thời gian chạy bạn nên sử dụng Runnable hoặc một Listener hoặc tương tự Determining the size of an Android view at runtime

+0

cách nhận boundayParams bên trong ImageButtonCustom – Nepster

3

Bạn nên sử dụng rootView.getX()rootView.getY() như bên trái và đầu phần đất ... và (rootView.getX() + rootView.getWidth()) như bên phải và (rootView.getY() + rootView.getHeight()) cho ranh giới dưới cùng.

Bạn phải viết logic ranh giới của mình trong onTouch() trong trường hợp ACTION_MOVE.

Hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan