Drag & Drop does not work properly with embedded EditText on Android API 24

134 views Asked by At

I have an app and it has been working well. However, after I upgraded the phone to Android 7.0, the drag and drop function was broken. And if I further upgrade the phone to Android 7.1, it works well again.

And then I created a test app to find out the cause, but I can only "prove" that it has something to do with the nested EditText inside a RelativeLayout.

Here is the code to show the log:

private class EntryHolder{
    View mEntryLayout;
    View mEntryContainer;
}

void addView() {
    EntryHolder eh = new EntryHolder();

    eh.mEntryLayout = getLayoutInflater()
            .inflate(R.layout.edit_item, mContainer, false);
    eh.mEntryContainer = eh.mEntryLayout.findViewById(R.id.field_container);
    eh.mEntryContainer.setTag(eh);
    eh.mEntryLayout.setTag(eh);
    mContainer.addView(eh.mEntryLayout, mIndex++);
    eh.mEntryContainer.setOnLongClickListener(this);
    eh.mEntryLayout.setOnDragListener(mDragListener);
}

private class DragListener implements View.OnDragListener {

    String[] ACTIONS = {"---", "STARTED   ", "LOCATION  ", "DROP      ",
            "ENDED     ", "ENTERED   ", "EXITED    "};

    @Override
    public boolean onDrag(View view, DragEvent dragEvent) {
        int action = dragEvent.getAction();
        Log.d("Drag&Drop", ACTIONS[action]+view.toString());
        switch(action) {
            case DragEvent.ACTION_DRAG_STARTED:
            case DragEvent.ACTION_DRAG_ENTERED:
            case DragEvent.ACTION_DRAG_ENDED:
            case DragEvent.ACTION_DRAG_LOCATION:
            case DragEvent.ACTION_DROP:
                return true;
        }
        return false;
    }

    @Override
public boolean onLongClick(View view) {
    ClipData not_used_clip = ClipData.newPlainText("", "");
    EntryHolder eh = (EntryHolder)view.getTag();
    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        eh.mEntryLayout.startDrag(not_used_clip, new View.DragShadowBuilder(eh.mEntryLayout),
                eh.mEntryLayout, 0);
    }
    else {
        eh.mEntryLayout.startDragAndDrop(not_used_clip, new View.DragShadowBuilder(eh.mEntryLayout),
                eh.mEntryLayout, 0);
    }
    view.setAlpha(0.0f);
    return true;
}

in onCreateView method of the test activity, addView is called 3 times to dynamically add 3 of the frame_layout.

If I put the frame_layout xml this way:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:elevation="8dp">
    <RelativeLayout android:id="@+id/field_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="4dp"
        android:paddingBottom="4dp"
        android:longClickable="true"
        android:background="@android:color/holo_blue_bright">
        <LinearLayout android:id="@+id/line1"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="36dp">
            <!--Something is supposed to be here-->
        </LinearLayout>
    <EditText
        android:id="@+id/field_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Value"
        android:layout_below="@id/line1"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
    </RelativeLayout>
</FrameLayout>

The output in logcat would simply be the following in Android API 24,

...D/Drag&Drop: STARTED   android.widget.FrameLayout{63144b4 ...
...D/Drag&Drop: STARTED   android.widget.FrameLayout{231eb23 ...
...D/Drag&Drop: STARTED   android.widget.FrameLayout{d141b9e ...
...D/Drag&Drop: ENDED     android.widget.FrameLayout{63144b4 ...
...D/Drag&Drop: ENDED     android.widget.FrameLayout{d141b9e ...
...D/Drag&Drop: ENDED     android.widget.FrameLayout{231eb23 ...

In other versions (including API 23- and API 25), the output would be much more with ENTERED, LOCATION and EXITED

If I remove the RelativeLayout in the middle or if I remove the EditText, then it is fine in API 24 as well. But I need that level of layout in my actual app so I cannot solve it this way.

Can anybody have any suggestions on the problem? Thank you!

0

There are 0 answers