Search code examples
androiddraggableontouchlistener

Smooth dragging of view


I have a activity which consists of toolbar, bottommenu (similar to instagram) and a small draggable relativeLayout at the right bottom of the screen of width and height = 500dp.

I have implemented drag on that relativeLayout as follows:

  public void touchListenerPip(RelativeLayout relativeLayoutPIP) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    float screenHeight = displayMetrics.heightPixels;
    float screenWidth = displayMetrics.widthPixels;
    relativeLayoutPIP.setOnTouchListener(new View.OnTouchListener() {
        @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;
                    if ((newX <= 0 || newX >= screenWidth - view.getWidth()) || (newY <= 0 || newY >= screenHeight - view.getHeight())) {
                        lastAction = MotionEvent.ACTION_MOVE;
                        break;
                    }
     //to block the view being dragged out of toolbar
                    if (newY < (float) toolbar.getHeight()) {
                        lastAction = MotionEvent.ACTION_MOVE;
                        break;
                    }
       //to block the view being dragged out of bottombar

                    if (event.getRawY() + (float) view.getHeight() > screenHeight - (float) bottomBar.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)
                        break;

                default:
                    return false;
            }
            return true;
        }
    });
}

The view is dragging fine and dragging is not smooth. Any suggestions for smooth dragging of view?


Solution

  • Got it to smoothly work with below code and also able to perform click on with

      private final static float CLICK_DRAG_TOLERANCE = 10; // Often, there will be a slight, unintentional, drag when the user taps the view, so we need to account for this.
    
    private float downRawX, downRawY;
    private float dX, dY;
    
    
    public void touchListenerPip(RelativeLayout relativeLayoutPIP) {
        relativeLayoutPIP.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                int action = event.getAction();
                if (action == MotionEvent.ACTION_DOWN) {
                    downRawX = event.getRawX();
                    downRawY = event.getRawY();
                    dX = view.getX() - downRawX;
                    dY = view.getY() - downRawY;
                    return true;
                } else if (action == MotionEvent.ACTION_MOVE) {
                    int viewWidth = view.getWidth();
                    int viewHeight = view.getHeight();
    
                    View viewParent = (View) view.getParent();
                    int parentWidth = viewParent.getWidth();
                    int parentHeight = viewParent.getHeight();
    
                    float newX = event.getRawX() + dX;
                    newX = Math.max(0, newX); // Don't allow the view past the left hand side of screen
                    newX = Math.min(parentWidth - viewWidth, newX); // Don't allow the view past the right hand side of screen
    
                    float newY = event.getRawY() + dY;
                    newY = Math.max(toolbar.getHeight(), newY); // Don't allow the view past the top of screen including toolbar
                    int bottomHeight = viewHeight + bottomBar.getHeight();
                    newY = Math.min(parentHeight - bottomHeight, newY); // Don't allow the view past the bottom of screen including bottombar
    
                    view.animate()
                            .x(newX)
                            .y(newY)
                            .setDuration(0)
                            .start();
    
                    return true;
    
                } else if (action == MotionEvent.ACTION_UP) {
    
                    float upRawX = event.getRawX();
                    float upRawY = event.getRawY();
    
                    float upDX = upRawX - downRawX;
                    float upDY = upRawY - downRawY;
    
                    if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
                        viewClick();
                        return true;
                    } else { // A drag
                        return true;
                    }
    
                }
                return true;
            }
        });
    }