Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PopupWindow doesn't respond to drag and drop events

I have a menu icon in my application. When I drag and drop something on it, it will show a popup. I need to extend my drag and drop to this PopupWindow.

I am doing this as below.

Created a PopupWindow as shown

View popupView = View.inflate(anchorView.getContext(), R.layout.layout_popup, null);

PopupWindow popUpWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT,
                                                  WindowManager.LayoutParams.WRAP_CONTENT);

And setting the dragListener as shown

popupView.setOnDragListener(new OnDragListener() {
            @Override
            public boolean onDrag(View view, DragEvent dragEvent) {



                    switch (dragEvent.getAction()) {
                    case DragEvent.ACTION_DRAG_STARTED:
                        Log.d("Drag", "ACTION_DRAG_STARTED");
                        break;
                    case DragEvent.ACTION_DRAG_ENDED:
                        Log.d("Drag", "ACTION_DRAG_ENDED");
                        break;
                    case DragEvent.ACTION_DRAG_ENTERED:
                        Log.d("Drag", "ACTION_DRAG_ENTERED");
                        break;
                    case DragEvent.ACTION_DRAG_EXITED:
                        Log.d("Drag", "ACTION_DRAG_EXITED");
                        break;
                    case DragEvent.ACTION_DROP:
                        Log.d("Drag", "ACTION_DROP");
                        break;
                    default:
                        break;
                    }

                return true;
            }
        });

Below video shows what I want to achieve.

enter image description here

But the popupView is not responding to any drag events. I also tried using the DialogFragment, but it didn't help either. Any help is appreciated.

Thanks in advance.

like image 291
heyjii Avatar asked May 03 '17 10:05

heyjii


1 Answers

PopupWindow will add the View on WindowManager instance, and not to the current layout. Whereas in the docs it is specified:

The system sends a drag event with action type ACTION_DRAG_STARTED to the drag event listeners for all the View objects in the current layout.

Pay attention to bolded "in the current layout". The content view of PopupWindow is not considered to be in the current layout, that's why those events are not dispatched to PopupWindow's content view.

As a workaround you can add a View with same coordinates to the current layout, which will act as a ghost of PopupWindow, and listen for drag events for this View.


Implementation

Add the ghost view to the layout:

<include android:id="@+id/ghost"
         layout="@layout/layout_popup"/>

Setup the ghost view from onCreate():



    private void setupGhostView() {
        ghost = findViewById(R.id.ghost);
        ghost.setAlpha(0.0f);
        ghost.findViewById(R.id.txt_append).setOnDragListener(new OnDragListener() {
            @Override
            public boolean onDrag(View v, DragEvent event) {
                if (event.getAction() == DragEvent.ACTION_DROP) {
                    Toast.makeText(MainActivity.this, "Settings 1", Toast.LENGTH_SHORT).show();
                }
                return true;
            }
        });
        ghost.findViewById(R.id.txt_replace).setOnDragListener(new OnDragListener() {
            @Override
            public boolean onDrag(View v, DragEvent event) {
                if (event.getAction() == DragEvent.ACTION_DROP) {
                    Toast.makeText(MainActivity.this, "Settings 2", Toast.LENGTH_SHORT).show();
                }
                return true;
            }
        });
    }


We do not want ghost view to be visible, that's why we set it's alpha to zero.

Then we setup the PopupWindow having anchor view:



    private void preparePopup(View anchorView) {
        final View popupView = View.inflate(anchorView.getContext(), R.layout.layout_popup, null);
        popupView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

        popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT);
        popupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
        popupWindow.setTouchable(false);

        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                popupView.getMeasuredWidth(), popupView.getMeasuredHeight());
        params.gravity = Gravity.END;
        ghost.setLayoutParams(params);
        ghost.invalidate();
        ghost.requestLayout();
    }


We need to perform setTouchable(false), otherwise PopupWindow will consume touch events. Also, we set ghost view's location exactly at the position where PopupWindow will be displayed.

Then we show and dismiss PopupWindow on appropriate drag events:



    menuView.setOnDragListener(new OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            int dragEvent = event.getAction();
            switch (dragEvent) {

                case DragEvent.ACTION_DRAG_ENTERED:
                    popupWindow.showAsDropDown(anchorView);
                    break;

                case DragEvent.ACTION_DRAG_ENDED:
                    popupWindow.dismiss();
                    break;
            }

            return true;
        }
    }); 


Result

enter image description here

A pull request is opened in your repo with abovementioned functionality.

like image 142
azizbekian Avatar answered Nov 13 '22 12:11

azizbekian