Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag and Drop and OnClick TextView

I'm creating drag and drop text view and I need this text view also can be clicked. My code as per below :

     <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/bg_grey"
        android:orientation="vertical" >

        <GridView
            android:id="@+id/gridview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@color/bg_grey"
            android:clickable="true"
            android:columnWidth="100dp"
            android:gravity="center"
            android:horizontalSpacing="10dp"
            android:numColumns="2"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp" />

        <TextView
            android:id="@+id/drag_drop_button"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginLeft="255dp"
            android:layout_marginTop="155dp"
            android:background="@drawable/circle_button"
            android:clickable="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            android:text="@string/brand"
            android:textColor="@color/sign_blue"
            android:textSize="15sp"
            android:textStyle="bold" />

    </FrameLayout>


class ButtonDragListener implements OnDragListener {
        Drawable normalShape = getResources().getDrawable(
                R.drawable.circle_button);

        @Override
        public boolean onDrag(View v, DragEvent event) {
            int action = event.getAction();
            switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                // do nothing
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                // do nothing
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                // do nothing
                break;
            case DragEvent.ACTION_DROP:
                // Dropped, reassign View to ViewGroup
                View view = (View) event.getLocalState();
                view.setX(event.getX());
                view.setY(event.getY());
                ViewGroup owner = (ViewGroup) view.getParent();
                owner.removeView(view);
                FrameLayout container = (FrameLayout) v;
                container.addView(view);
                view.setVisibility(View.VISIBLE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                // do nothing
                break;
            default:
                break;
            }
            return true;
        }
    }

        private final class ButtonTouchListener implements OnTouchListener {

            private static final int MAX_CLICK_DURATION = 200;
            private long startClickTime;

            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    startClickTime = Calendar.getInstance().getTimeInMillis();
                    ClipData data = ClipData.newPlainText("", "");
                    DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                            view);
                    view.startDrag(data, shadowBuilder, view, 0);
                    view.setVisibility(View.VISIBLE);

                } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                    long clickDuration = Calendar.getInstance().getTimeInMillis()
                            - startClickTime;

                    if (clickDuration < MAX_CLICK_DURATION){ 
                        view.performClick();
                    }
                }
                return true;
            }
        }

        private final class ButtonOnClickListener implements OnClickListener {

            @Override
            public void onClick(View v) {
                Log.e(TAG, "ALOHAAAAA");

            }

        }

        TextView dragDrop = (TextView) view.findViewById(R.id.drag_drop_button);
            dragDrop.setAlpha(0.7f);
            dragDrop.setOnClickListener(new ButtonOnClickListener());
            dragDrop.setOnTouchListener(new ButtonTouchListener());
        frameLayout = (FrameLayout) view.findViewById(R.id.root);
        frameLayout.setOnDragListener(new ButtonDragListener());

But MotionEvent.ACTION_UP never be called, I'm also trying to move view.performClick() inside MotionEvent_ACTION_DOWN, the click listener calling fine but whenever I'm dragging the text view the click listener also run. I also have setOnTouchListener and setOnClickListener directly from textView but the result is same.

What I need here is smooth drag and drop and also click function. Kindly advise what I'm doing wrong here. Thank you and really appreciate for any kind help.

like image 239
Vierda Mila Nartila Avatar asked Feb 14 '23 08:02

Vierda Mila Nartila


2 Answers

I have the same problem as you, your solution is not quite helping me, so I came up with this solution, it's based on your previous solution.

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (Math.abs(event.getX() - mX) < MAX_X_MOVE || Math.abs(event.getY() - mY) < MAX_Y_MOVE) {
                v.performClick();
            } else {
                ClipData clipData = ClipData.newPlainText("", "");
                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
                v.startDrag(clipData, shadowBuilder, v, 0);
                v.setVisibility(View.INVISIBLE);

                mX = event.getX();
                mY = event.getY();
            }

            return true;
        }
        return false;
    }
like image 86
Bilal Avatar answered Feb 23 '23 06:02

Bilal


This is a kind of a problem where although there is provided solutions, but also you have to think of how these solutions will fit your needs. For my case I used the ideas above and came up with my own solution that fits my needs.

  /**
   * Max value of X to move before we declare that we are going to do
   * drag. 
   */
   private static final float MAX_X_MOVE = 120;

  /**
   * Max value of Y to move before we declare that we are going to do 
   * drag.
   */
   private static final float MAX_Y_MOVE = 120;

   private final static int NONE = 0;

   private final static int DRAG = 1;

   private int m_mode = NONE;

   icon.setOnTouchListener(new View.OnTouchListener() {
     @Override
     public boolean onTouch(View v, MotionEvent event) {

        final int action = event.getAction();

         switch (action){
           case MotionEvent.ACTION_DOWN:
            m_mode = NONE;
           break;

           case MotionEvent.ACTION_MOVE:
             if (Math.abs(event.getX()) > MAX_X_MOVE || 
                 Math.abs(event.getY()) > MAX_Y_MOVE) {
                 m_mode = DRAG;
                 _startDragOnFling();
             }
           break;

           case MotionEvent.ACTION_UP:
              if(m_mode == DRAG){
               break;
              }
              v.performClick();
           break;
         }

        return true;
      }
   });
like image 31
CodeDaily Avatar answered Feb 23 '23 04:02

CodeDaily