16

I would like to move two different views into my layout, so that an user can display it like his wishes.

So far I've made the following code to handle the touch event:

this.viewEvent.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent event)
    {           
        final int y = (int) event.getRawY();

        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
        switch (event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                element.setEventY(y - params.topMargin);
                break;

            case MotionEvent.ACTION_UP:
                viewGroup.invalidate();
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                break;

            case MotionEvent.ACTION_MOVE:
                params.topMargin = y - element.getEventY();
                params.bottomMargin = screenHeight - view.getHeight() - params.topMargin;

                // Avoid out of screen
                if (params.topMargin < 0) return true;

                // Apply changes
                view.setLayoutParams(params);
                break;
        }

        return true;
    }
});

element is an instance of a custom object to handle the position. screenHeight is the screen height given by the Display class.

I'm able to move the element but it's blinking when I touch it and once I put my finger up, the view just disapear. I can't even retrieve it, it's just out of the screen.

Did I make something wrong ?

Thanks for your help

Anubian Noob
  • 13,426
  • 6
  • 53
  • 75
Manitoba
  • 8,522
  • 11
  • 60
  • 122
  • Here is the answer [android: move a view on touch move (ACTION_MOVE)](http://stackoverflow.com/questions/9398057/android-move-a-view-on-touch-move-action-move/31094315#31094315) – Andrew Oct 19 '15 at 13:16
  • Here is an example http://thegeekyland.blogspot.com/2015/12/android-animations-explained.html – Arlind Hajredinaj Dec 06 '15 at 13:45

3 Answers3

21

USe the following code to perform a simple Touch to move:

layout_counter.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent event)
        {
            if (currentState != State.EDIT_MOVE) return false;

            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
            if (view.getId() != R.id.layout_counter) return false;

            switch (event.getAction())
            {
                case MotionEvent.ACTION_MOVE:
                    params.topMargin = (int) event.getRawY() - view.getHeight();
                    params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
                    view.setLayoutParams(params);
                    break;

                case MotionEvent.ACTION_UP:
                    params.topMargin = (int) event.getRawY() - view.getHeight();
                    params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
                    view.setLayoutParams(params);
                    break;

                case MotionEvent.ACTION_DOWN:
                    view.setLayoutParams(params);
                    break;
            }

            return true;
        }
    });

Where layout_counter is the view you want to move.

Don't forget to put your movable elements into a FrameLayout

Manitoba
  • 8,522
  • 11
  • 60
  • 122
  • 4
    FrameLayout is here VERY important to use. I lost whole day using relative layout trying to figure out why just one of my image views is draggable and others shows logs on touch but they don't move.. :( Thanks – Ewoks Aug 10 '14 at 15:40
  • 1
    It show attempt to invoke a virtual method because of null pointer even though I have declared the framelayout – Jeff Bootsholz Feb 11 '15 at 08:34
  • 2
    What is State.EDIT_MOVE and currentState in the answer. Can you explain? – Ajeet Mar 06 '16 at 08:09
  • It's a State of an `enum` I used in my code to use a button to enable/disable the drag. – Manitoba Mar 07 '16 at 09:03
  • can I add relative layout into frame layout to move whole relative layout? – Pratik PSB Mar 22 '21 at 11:27
3

I created the library, which moves the view:

  • For API lower than JellyBean (16) it modifies the view's margins within its parent container
  • For API JellyBean and higher it modifies the absolute view position within its parent container

Just add the dependency:

dependencies {
    compile 'com.scalified:viewmover:1.1.0'
}

More info you can find on GitHub

1

I will provide an alternative solution for those who use Relative layout for example.

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class MainActivity extends Activity implements View.OnTouchListener
{
    private int       _xDelta;
    private int       _yDelta;
    private int       _rightMargin;
    private int       _bottomMargin;
    private ImageView _floatingView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this._floatingView = (ImageView) findViewById(R.id.textView);

        this._floatingView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            @Override
            public boolean onPreDraw()
            {
                if (_floatingView.getViewTreeObserver().isAlive())
                    _floatingView.getViewTreeObserver().removeOnPreDrawListener(this);

                updateLayoutParams(_floatingView);
                return false;
            }
        });

        this._floatingView.setOnTouchListener(this);
    }

    private void updateLayoutParams(View view)
    {
        this._rightMargin = -view.getMeasuredWidth();
        this._bottomMargin = -view.getMeasuredHeight();

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getMeasuredWidth(), view.getMeasuredHeight());
        layoutParams.bottomMargin = this._bottomMargin;
        layoutParams.rightMargin = this._rightMargin;

        view.setLayoutParams(layoutParams);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event)
    {
        if (view == this._floatingView)
        {
            final int X = (int) event.getRawX();
            final int Y = (int) event.getRawY();

            switch (event.getAction() & MotionEvent.ACTION_MASK)
            {
                case MotionEvent.ACTION_DOWN:
                    RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    this._xDelta = X - lParams.leftMargin;
                    this._yDelta = Y - lParams.topMargin;
                    break;

                case MotionEvent.ACTION_MOVE:
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    layoutParams.leftMargin = X - this._xDelta;
                    layoutParams.topMargin = Y - this._yDelta;
                    layoutParams.rightMargin = this._rightMargin;
                    layoutParams.bottomMargin = this._bottomMargin;
                    view.setLayoutParams(layoutParams);
                    break;
            }

            return true;
        }
        else
        {
            return false;
        }
    }
}
Ayaz Alifov
  • 8,334
  • 4
  • 61
  • 56