2

In a nutshell, I want to give users the ability to drag and drop EditText - however, when the EditText is released instead of dropping it disappears for some reason and I get the message:

I/ViewRootImpl﹕ Reporting drop result: false

I have an Activity with 2 FrameLayout's, camera_preview and bottom_toolbar like so:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_above="@+id/bottom_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
        android:id="@+id/bottom_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_alignParentBottom="true">

    </FrameLayout>
</RelativeLayout>

When bottom_toolbar is tapped, it is replaced by a Fragment who's XML contains a LinearLayout holding 2 EditTexts. I have set touch and drag listeners for these EditText's in onCreate() and added these classes to the said Fragment:

private final class MyTouchListener implements View.OnTouchListener {
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            ClipData data = ClipData.newPlainText("", "");
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
            view.setVisibility(View.INVISIBLE);
            view.startDrag(data, shadowBuilder, view, 0);
            return true;
        }
        else
        {
            return false;
        }
    }
}

class MyDragListener implements View.OnDragListener {
    private android.widget.LinearLayout.LayoutParams layoutParams;

    @Override
    public boolean onDrag(View v, DragEvent event) {
        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                layoutParams = (LinearLayout.LayoutParams) v.getLayoutParams();
                Log.d("TAG", "Started");
            break;
            case DragEvent.ACTION_DRAG_ENTERED:
                int x_cord = (int) event.getX();
                int y_cord = (int) event.getY();
                Log.d("TAG", "Entered");
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                x_cord = (int) event.getX();
                y_cord = (int) event.getY();
                layoutParams.leftMargin = x_cord;
                layoutParams.topMargin = y_cord;
                v.setLayoutParams(layoutParams);
                Log.d("TAG", "Exited");
                break;

            case DragEvent.ACTION_DRAG_LOCATION:
                x_cord = (int) event.getX();
                y_cord = (int) event.getY();
                Log.d("TAG", "Loc");
                break;

            case DragEvent.ACTION_DRAG_ENDED:
                //((View)event.getLocalState()).setVisibility(View.VISIBLE);
                v.setVisibility(View.VISIBLE);
                Log.d("TAG", "Ended");
                break;

            case DragEvent.ACTION_DROP:
                v.setVisibility(View.VISIBLE);
                Log.d("TAG", "Dropped");
                break;
            default:

            break;
        }
        return true;
    }

}  

Does anybody know why my EditTexts disappear when I drop them? I have spent countless hours online looking for a solution, but none of them seem to work.

Appreciate any advice, thanks.

EDIT:

Changed my drag listener to this:

class MyDragListener implements View.OnDragListener {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            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:
                    View view = (View) event.getLocalState();
                    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:
                default:
                    break;
            }
            return true;
        }
    }

I removed the drag listener from my EditText (kept the touch listener) and added it to the view I want to drop them in instead. I no longer get the false drop message and I'm certain it's dropping the EditText's because the fragment gets smaller when they are dragged out of it. I still can't see them though. Could it be that they are being dropped BEHIND the view instead of in front of it? If so, how can I avoid that? Thanks again.

Edit: bump

eyes enberg
  • 556
  • 1
  • 8
  • 30

1 Answers1

1

Looking at the Android source, Reporting drop result: false is a direct result from the dispatchDragEvent() call.

A cursory scan of this call within the ViewGroup class seems to indicate that the child views of a ViewGroup are searched for one that can accept the drop - if no child view returns true from dispatchDragEvent(), the drop is aborted.

In your question, you state: I have set touch and drag listeners for these EditText's..., but have you set any drag listeners for the layouts on which the EditText's are dropped?

My guess (and it is a guess!) is that the layouts themselves on which an EditText is being dropped are being queried for a drop handler, but none exist. In other words, you need to set a drag listener on the layout(s) being dropped on to - and return true from it.

Edit

I've created an App using the same code as you've posted and I see the same result as you - the EditText is moved, but is no longer visible.

I think there's a couple of things going on here. Firstly, it seems that you need to make the receiving FrameLayout focusable before you drop the EditText onto it:

case DragEvent.ACTION_DROP:
  View view = (View) event.getLocalState();
  ViewGroup owner = (ViewGroup) view.getParent();
  owner.removeView(view);
  FrameLayout container = (FrameLayout) v;
  // make it focusable first
  container.setFocusable(true);
  // now add the view
  container.addView(view);
  view.setVisibility(View.VISIBLE);
  break;

Secondly, you are passing the complete EditText as the localstate object - I don't think you should do this. From the docs, it seems that localstate should be something simple - I would advise making it the id of the EditText that's being dragged and use findViewById() when dropping to get the correct view.

For future reference, pick better variable names and try to comment your code. It's really quite hard to figure out what is going on when you name your variables view!

In any case, calling setFocusable() before adding the EditText makes it work on my device. An answer to this question also does it.

Community
  • 1
  • 1
adelphus
  • 10,116
  • 5
  • 36
  • 46
  • Hey thanks for this, I followed your advice and made some progress. The EditText's are now definitely being dropped, I just can't see them (suspecting that they are being dropped behind the target view). Can you look at my edit? – eyes enberg Aug 27 '15 at 14:04
  • @eyesenberg added reply – adelphus Aug 27 '15 at 15:22
  • Still not working for some reason. When I change the FrameLayout to a LinearLayout it displays the elements but on the top left instead of where the drag is released. With RelativeLayout its the same result as FrameLayout. – eyes enberg Aug 27 '15 at 23:46