7

Я создал перетаскиваемый вид внутри RelativeLayout. Но, похоже, он выходит за рамки RelativeLayout.Связано a Просмотр для перетаскивания внутри RelativeLayout

Я просто хочу, чтобы сделать вид перемещаемой внутри ViewGroup

И это мнение draggable в соответствии с экрана. И он перетаскивается за пределы RelativeLayout. Как я могу ограничить его, чтобы оставаться перетаскиваемым в 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:

ImageButton является Draggable, но она идет outside of parent. Restrict его перетащить в родительский макет.

+0

также попытался http://stackoverflow.com/ вопросы/21662397/how-to-keep-an-image-in-layout-with-drag-and-drop – Nepster

ответ

9

Вот выдержка из моих старых дневников. Надеюсь, это сработает для вас.

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

И вы можете установить его с помощью:

myView.setOnTouchListener(new OnDragTouchListener(myView)); 

Или путем добавления этого непосредственно в init метод вашего пользовательского вида:

setOnTouchListener(new OnDragTouchListener(this)); 
+0

myView.setOnTouchListener (новый OnDragTouchListener (myView, myParentView)); wroks спасибо – Nepster

+0

Отлично! Спасибо чувак! – belphegor

+0

Привет, хороший сниппет ... Как добавить onClickListener в тот же вид с той же функциональностью? – AndiM

1

В OnTouch рассчитать, куда двигаться ваш взгляд

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

Вы должны проверить границы для х и у перед его перемещением.

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

И вычислить границы вашего RelativeLayout на время выполнения следует использовать Runnable или прослушивателя или аналогичный Determining the size of an Android view at runtime

+0

как получить boundayParams внутри ImageButtonCustom – Nepster

3

Вы должны использовать rootView.getX() и rootView.getY() как левый и верхний bounderies ... и (rootView.getX() + rootView.getWidth()), как справа и (rootView.getY() + rootView.getHeight()) для нижней границы.

Вы должны написать свою граничную логику в onTouch() в случае ACTION_MOVE.

Надеюсь, это поможет.