1

I am trying to move the TextView around on the screen on my android app. But after dragging the TextViewto final position, Its randomly moving to other opposition.


private final class TextViewTouchListener implements View.OnTouchListener {

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                ClipData data = ClipData.newPlainText("", "");
                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
                //start dragging the item touched
                view.startDrag(data, shadowBuilder, view, 0);
                return true;
            }
        }


private final class TextViewDragListener implements View.OnDragListener {

            @Override
            public boolean onDrag(View v, DragEvent event) {
                final float x = event.getX();
                final float y =event.getY();

// handling the case when the textview gets dragged out of screen
                leftMargin = Math.min(x, mDisplaySize.x - textview.getWidth());
                topargin = Math.min(y, mDisplaySize.y - textview.getHeight());

                final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) textView.getLayoutParams();
                params.leftMargin = (int) leftMargin;
                params.topMargin = (int) topargin;
                params.rightMargin = 0;
                params.bottomMargin = 0;

            textView.setLayoutParams(params);

                return true;
            }
        }

Seems like I am handling it wrong. Can someone help me what exactly I am doing wrong.
Zain
  • 37,492
  • 7
  • 60
  • 84
Sandy K
  • 65
  • 1
  • 1
  • 8

1 Answers1

1

If you just want to move the view around the screen, no need to use drag/drop; you just can update the view x & y location on the screen using the MotionEvent.ACTION_DOWN & MotionEvent.ACTION_MOVE events of View.OnTouchListener.

And to avoid moving the view off the screen, then we will calculate width & height of the root view using its getViewTreeObserver()

So, your layout would have a root view holding a TextView which you want to move around the screen.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World" />

</RelativeLayout>

And your behaviour will be:

public class MainActivity extends AppCompatActivity {

    private int mXDelta = 0;
    private int mYDelta = 0;
    private int mRootWidth;
    private int mRootHeight;

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

        final RelativeLayout rootLayout = findViewById(R.id.root_layout);

        rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    rootLayout.getViewTreeObserver()
                            .removeOnGlobalLayoutListener(this);
                }

                mRootWidth = rootLayout.getWidth();
                mRootHeight = rootLayout.getHeight();
            }
        });

        TextView textView = findViewById(R.id.textview);
        textView.setOnTouchListener(mOnTouchListener);


    }

    View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent event) {

            int xScreenTouch = (int) event.getRawX(); // x location relative to the screen
            int yScreenTouch = (int) event.getRawY(); // y location relative to the screen

            switch (event.getAction() & MotionEvent.ACTION_MASK) {

                case MotionEvent.ACTION_DOWN:
                    RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    mXDelta = xScreenTouch - lParams.leftMargin;
                    mYDelta = yScreenTouch - lParams.topMargin;
                    break;

                case MotionEvent.ACTION_MOVE:
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
                            .getLayoutParams();

                    layoutParams.leftMargin = Math.max(0, Math.min(mRootWidth - view.getWidth(), xScreenTouch - mXDelta));
                    layoutParams.topMargin = Math.max(0, Math.min(mRootHeight - view.getHeight(), yScreenTouch - mYDelta));
                    view.setLayoutParams(layoutParams);
                    break;
            }

            return true;
        }
    };

}

Result

Zain
  • 37,492
  • 7
  • 60
  • 84
  • Thanks @Zain for your promt response. Its really helpful. One follow-up question, why dint you handle MotionEvent.ACTION_UP case? – Sandy K Apr 20 '20 at 18:03
  • Hi @SandyK, cool for that, I guess no need as you just moving the object, and as long as your finger on the screen, then the `onTouch()` is always called and the switch case of the `MotionEvent.ACTION_MOVE ` is sufficient to keep the `TextView` moving – Zain Apr 20 '20 at 18:11
  • Thanks @Zain, One point thet confused me is if ACTION_MOVE is sufficient to move the textview around, then why did we need to Handle DOWN separately ? – Sandy K Apr 20 '20 at 18:59
  • @SandyK because you want to know where the user hits the TextView on the screen once they get touched the screen to manipulate that each time you move the text, and this is handled with mXDelta & mYDelta values in the code – Zain Apr 20 '20 at 19:16