Prevent drag drop of custom mimetype to EditText

2020-07-05 07:04发布

I have a custom mime type which I am intending to use to drag and drop application objects within the app. This seems to be working but I'm finding that the EditText fields are also accepting the drop action. I don't want this to happen.

First, I've defined the custome mime type like this:

public static final String MIME_TYPE_MYNODE = "com.example.mockup/mynode";

Then, in the onTouch handler for the source object I have:

  @Override
  //-----------------------------------------------------------------------------
  public boolean onTouch (View v, MotionEvent e)
  {
    ...
    else if (e.getAction() == MotionEvent.ACTION_MOVE)
    {
      String[] mimeTypes = {MIME_TYPE_MYNODE};
      ClipData data = new ClipData ("Task Tamer Note", mimeTypes, new ClipData.Item ("unused"));
      View.DragShadowBuilder shadow = new View.DragShadowBuilder(this);
      Object localState = v;
      startDrag (data, shadow, localState, 0);
      return false;
    }
  }
  ...
}

When I "drop" on an EditText widget, it inserts "unused" into the text area. How can I prevent this? Thanks.

4条回答
太酷不给撩
2楼-- · 2020-07-05 07:42

You may write

edit.setEnabled(false);
edit.setFocusable(false);

just after calling startDrag(), and restore old values for that particular editText control just after DragEvent.ACTION_DRAG_ENDED.

But, honestly, this is quite dirty approach.

查看更多
Viruses.
3楼-- · 2020-07-05 07:50

I encountered the same behaviour. I have found the reason, which is located in TextView class.

The method onDragEvent(DragEvent event) is overrriden here and looks as below.

@Override
public boolean onDragEvent(DragEvent event) {
    switch (event.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED:
            return mEditor != null && mEditor.hasInsertionController();

        case DragEvent.ACTION_DRAG_ENTERED:
            TextView.this.requestFocus();
            return true;

        case DragEvent.ACTION_DRAG_LOCATION:
            final int offset = getOffsetForPosition(event.getX(), event.getY());
            Selection.setSelection((Spannable)mText, offset);
            return true;

        case DragEvent.ACTION_DROP:
            if (mEditor != null) mEditor.onDrop(event);
            return true;

        case DragEvent.ACTION_DRAG_ENDED:
        case DragEvent.ACTION_DRAG_EXITED:
        default:
            return true;
    }
}

If it is possible to insert text => EditText then any drag will be processed and accepted there. The View class is not using OnDragListener, so it is not possible to prevent this behaviour by

editText.setOnDragListener(null);

The solution here is to subclass the EditText as here and override onDragEvent() method:

 public class YourEditText extends EditText {

 ...
 // other stuff
 ...

 @Override
 public boolean onDragEvent(DragEvent event) {
    switch (event.getAction()) {
       case DragEvent.ACTION_DRAG_STARTED:
           if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
               return true;
           }
           return false;
       default:
           return super.onDragEvent(event);
    }
}

}

Now YourEditText will accept only drags with MIMETYPE_TEXT_PLAIN. If you want to disable the drag drop at all just return false in this method`

@Override
public boolean onDragEvent(DragEvent event) {
    return false;    
}

And that's it. Hope it will help.

查看更多
放我归山
4楼-- · 2020-07-05 07:50

Returns true if the drag event was handled successfully, or false if the drag event was not handled. Note that false will trigger the View to call its onDragEvent() handler.

This is statement from the docs of onDrag(View v, DragEvent event). So if you return false then the event is handled by onDragEvent() of EditText. Hence the simplest solutions is:

editText.setOnDragListener(new OnDragListener() {

        @Override
        public boolean onDrag(View v, DragEvent event) {
            return true;
        }
    });

In case you would like to perform some functions, specify based on the Drag event and they will be executed.

查看更多
三岁会撩人
5楼-- · 2020-07-05 07:54

I encountered a similar issue in that I did not want a layout to accept the drop action.

Attach a drag listener to your edit field via the setOnDragListener.

edtText.setOnDragListener(new MyDragListener());

Check whether the target view in the onDrag event is your edit text.

class MyDragListener implements OnDragListener {

    @Override
    public boolean onDrag(View v, DragEvent event) {

      switch (event.getAction()) {
         case DragEvent.ACTION_DROP:
             //check whether it has been dropped onto your edit text
              if(v!=edtText)
                  //your code here
    }
查看更多
登录 后发表回答