弹出窗口不响应拖放事件

3

我在我的应用程序中有一个菜单图标。当我将某物拖放到它上面时,它会显示一个弹出窗口。我需要将我的拖放扩展到这个 PopupWindow

我是这样做的。

创建了一个如下所示的 PopupWindow

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

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

将dragListener设置如下所示

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;
            }
        });

以下视频展示了我想要实现的内容。

enter image description here

但是弹出视图没有响应任何拖动事件。我也尝试使用DialogFragment,但也没有帮助。非常感谢您的帮助。
1个回答

2

PopupWindow 会将 View 添加到 WindowManager 实例,而不是当前的布局中。然而文档中指定:

系统向当前布局中的所有 View 对象的拖动事件监听器发送具有操作类型 ACTION_DRAG_STARTED 的拖动事件。

注意加粗的 "在当前布局中"。 PopupWindow 的内容视图不被认为在当前布局中,因此这些事件不会分派到 PopupWindow 的内容视图上。

作为解决方法,您可以将具有相同坐标的 View 添加到当前布局中,它将充当 PopupWindow 的虚影,并监听此 View 的拖动事件。


实现

ghost view添加到布局中:

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

onCreate()中设置ghost view



    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;
            }
        });
    }


我们不希望ghost view可见,所以将其透明度设置为零。

然后我们设置具有锚点视图的PopupWindow



    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(); }

我们需要执行setTouchable(false),否则PopupWindow将会消耗触摸事件。此外,我们将ghost view的位置设置在PopupWindow将要显示的位置。

然后,在适当的拖动事件上,我们显示和关闭PopupWindow



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; } });

enter image description here

您的存储库中打开了一个拉取请求,其中包含上述功能。


1
感谢您的回复。我需要的与您提出的不同。我已经添加了一个gif来更好地定义它。再次感谢您的编辑。 - heyjii
如果我理解正确,您正在拖动一个“按钮”而不是“弹出窗口”。为什么您希望“弹出窗口”的拖动回调被触发呢?您并没有在拖动“弹出窗口”,对吧? - azizbekian
根据文档 https://developer.android.com/reference/android/view/View.html#startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int),它说:“一旦系统拥有了拖影,它就会通过向应用程序中所有当前可见的 View 对象发送拖放事件来开始拖放操作。”这意味着可以将其拖放到在拖动开始时可见的视图上... - heyjii
当您拖动按钮时,每当发生DragEvent.ACTION_DRAG_ENDED事件时,请执行contentView.dispatchDragEvent(dragEvent); - azizbekian
contentView.dispatchDragEvent(dragEvent) 只是简单地派发拖动事件而不考虑它是否在弹出窗口之上... 不管怎样,感谢您的建议... 我会基于那个寻找解决方案... - heyjii
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接