Question

I have one button and i can drag it anywhere on the screen, but it is going outside the screen while dragging, so how to drag only inside the screen, so that it should not go out of the screen

Button.setOnTouchListener(new TextView.OnTouchListener() {
        public boolean onTouch(View view, MotionEvent event) {              

            X_button = (int) event.getRawX();
            Y_button= (int) event.getRawY();


            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:

                RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                _xDelta = X_button - lParams.leftMargin;
                _yDelta = Y_button - lParams.topMargin;
                break;
            case MotionEvent.ACTION_UP:                 
                 if(!isMoving)
                 {
                    view.performClick();                        
                 }  

                 isMoving=false;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
            case MotionEvent.ACTION_MOVE:                   
                isMoving=true;                  
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
                        .getLayoutParams();
                layoutParams.leftMargin = X_button - _xDelta;
                layoutParams.topMargin = Y_button - _yDelta;
                layoutParams.rightMargin = -250;
                layoutParams.bottomMargin = -250;
                view.setLayoutParams(layoutParams);

                break;
            }
            return true;
        }
    });
Was it helpful?

Solution

First, use the methods View.setX(), View.setY(), View.setTranslateX(), View.setTranslateY() for moving Views on screen instead of updating margins of LayoutParams. I've found them to perform way more smoother.

Second, for limiting the views to your available window, get the available window size using the following function:

DisplayMetrics metrics = getResources().getDisplayMetrics();
int windowWidth = metrics.widthPixels;
int windowHeight = metrics.heightPixels

Next, in your onTouch method, calculate if the target location exceeds the above dimensions. For example:

if( currentXLocation + deltaX > windowWidth ){

    // this will ensure that target location 
    // is always <= windowHeight
    deltaX = windowWidth - currentXLocation; 

} else if( currentXLocation + deltaX < 0){

    deltaX = -(currentXLocation);

} else if (...){

    // perform similar calculations for the rest 

}

OTHER TIPS

Modify OnTouch listerner section as :

 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 screenHight = displaymetrics.heightPixels;
 screenWidth = displaymetrics.widthPixels;

  @SuppressLint("NewApi") @Override
  public boolean onTouch(View view, MotionEvent event) {


       float newX, newY;

    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:

        dX = view.getX() - event.getRawX();
        dY = view.getY() - event.getRawY();
        lastAction = MotionEvent.ACTION_DOWN;
        break;

      case MotionEvent.ACTION_MOVE:

          newX = event.getRawX() + dX;
          newY = event.getRawY() + dY;

      // check if the view out of screen
          if ((newX <= 0 || newX >= screenWidth-view.getWidth()) || (newY <= 0 || newY >= screenHight-view.getHeight()))
          {
              lastAction = MotionEvent.ACTION_MOVE;
              break;      
          }

        view.setX(newX);
        view.setY(newY);

        lastAction = MotionEvent.ACTION_MOVE;

        break;

      case MotionEvent.ACTION_UP:
        if (lastAction == MotionEvent.ACTION_DOWN)
          Toast.makeText(DraggableView.this, "Clicked!", Toast.LENGTH_SHORT).show();
        break;

      default:
        return false;
    }
    return true;
  }

Refer this solution, when dragging the image stays on the screen. https://stackoverflow.com/a/36417605/4324288

Signed up just to answer this because of the frustration of finding the same, unfortunately wrong, answer all over the internet.

To handle your object being drawn outside of the view, set up an OnDragListener for the object then call a handler from there - it will crash if you don't use a handler - and pass the view ID to the handler. Except, I found that your user can also muck up the works by touching two buttons at exactly the same time and when you switch activities if the user is touching the screen then you can lose objects that way too - so what worked best was that my handler is called from the drag listener ACTION_DRAG_ENDED and touch listener ACTION_UP just makes sure that everything that should be visible is. This way every time the user stops touching the screen it will fix whatever he/she did.

private final class MyTouchListener implements OnTouchListener {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                ClipData data = ClipData.newPlainText("", "");
                DragShadowBuilder shadowBuilder = new DragShadowBuilder(view);
                view.startDrag(data, shadowBuilder, view, 0);
                view.setVisibility(View.INVISIBLE);
                return true;
            case MotionEvent.ACTION_UP:
                drophandler.sendEmptyMessage(0);
            case MotionEvent.ACTION_MOVE:
                return true;
            default:
                break;
            }
        return true;
    }
}

class MyDragListener implements OnDragListener {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        View view = (View) event.getLocalState();
        Button drag = (Button) view;
        int action = event.getAction();

        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                Button target = (Button) v;
                //do stuff
                return true;
            case DragEvent.ACTION_DRAG_ENDED:
                drophandler.sendEmptyMessage(0);
                return true;
            default:
                break;
        }
        return true;
    }
}

private Handler drophandler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        for(int x = 0; x < 3 + difficulty; x++){
            for(int y = 0; y < 5 + difficulty; y++){
                if (buttons[x][y] != null){
                    buttons[x][y].setVisibility(View.VISIBLE);
                }
            }
        }
    }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top