7

Utworzono widok przeciągalny wewnątrz RelativeLayout. Ale wydaje się, że wykracza poza RelativeLayout.Związany widok, aby przeciągnąć wewnątrz RelativeLayout

ja po prostu chce dokonać View Draggable wewnątrz ViewGroup

I ten pogląd jest draggable według Screen. I jest przeciągalny poza granice RelativeLayout. W jaki sposób mogę ograniczyć to, aby pozostać przeciągalnym w 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 jest Draggable ale idzie outside of parent. Ograniczenie to przeciągnij w swoim macierzystym układzie.

+0

próbował również http://stackoverflow.com/ pytania/21662397/how-to-keep-an-image-in-layout-with-drag-and-drop – Nepster

Odpowiedz

9

Oto wyciąg z moich starych pamiętników. Mam nadzieję, że to działa dla ciebie.

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

I można ustawić za pomocą:

myView.setOnTouchListener(new OnDragTouchListener(myView)); 

Albo dodając ten bezpośrednio w init metodę widoku niestandardowego:

setOnTouchListener(new OnDragTouchListener(this)); 
+0

myView.setOnTouchListener (new OnDragTouchListener (myView, myParentView)); wroks dzięki – Nepster

+0

Świetnie! dzięki! – belphegor

+0

Hi nice snippet ... Jak dodać onClickListener do tego samego widoku z tej samej funkcjonalności? – AndiM

1

W OnTouch obliczyć gdzie przenieść swój pogląd

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

Należy sprawdzić granice dla X i Y przed przeniesieniem.

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

I obliczyć granice swojej RelativeLayout w czasie wykonywania należy użyć Runnable lub słuchacza lub podobny Determining the size of an Android view at runtime

+0

jak zdobyć boundayParams wewnątrz ImageButtonCustom – Nepster

3

Należy używać rootView.getX() i rootView.getY() jako Granic lewej i góry ... i (rootView.getX() + rootView.getWidth()) jako prawą i (rootView.getY() + rootView.getHeight()) dla dolnej granicy.

Musisz napisać swoją logikę graniczną w onTouch() w przypadku ACTION_MOVE.

Mam nadzieję, że to pomoże.

Powiązane problemy