在 Android 中不会阻止拖放的不显眼的弹出窗口

Posted

技术标签:

【中文标题】在 Android 中不会阻止拖放的不显眼的弹出窗口【英文标题】:Unobtrusive popup that won't block drag n drop in Android 【发布时间】:2016-04-03 12:44:36 【问题描述】:

我一直在开发类似于 nova 启动器的 android 启动器应用程序。我已经设置了 OnItemLongClickListener 和 OnDragListener。当我长按一个图标时,会显示一个弹出窗口,其中包含“删除”、“更改图标”等菜单。下图显示了应用程序在长按时打开弹出窗口的进度。

问题是当弹出窗口打开时,拖放工作但不工作。一旦弹出窗口打开,似乎 i 无法记录 x、y 位置。此外,当执行 drop 时,logcat 中会显示以下消息。

I/ViewRootImpl: Reporting drop result: false

我的代码在 OnDragListener 中是这样的

public boolean onDrag(View v, DragEvent event) 
int dragEvent = event.getAction();
switch (dragEvent)
    
        case DragEvent.ACTION_DRAG_LOCATION:
        //Open popup here; note: its opened only once. popup.show();
        //Log.i("Position x : ", Float.toString(event.getX())); log x or y

        /*code to detect x any y change amount and close the popup
          once user drags the icon little further and app knows that
          user is trying to drag instead of opening the popup
          and hence close the popup. popup.dismiss();
        */

        // other case like ACTION_DROP etx goes after this
    
 

但似乎在弹出窗口打开后我无法记录 x 或 y;也无法运行确定该操作是用于“拖动”还是“弹出打开”的代码。

那么我该如何解决这个问题呢?一旦任何拖动量足以知道用户想要拖动,我想关闭弹出窗口。如果不停止拖动并仅显示弹出窗口。

编辑

我通过使用 OnTouchListner 和 OnDragListner 解决了弹出窗口的问题。下面显示了我的 OnDragListner 代码。

//bottomAppDrawer is a GridView
bottomAppDrawer.setOnDragListener(new View.OnDragListener() 
        @Override
        public boolean onDrag(View v, DragEvent event) 
            int dragEvent = event.getAction();
            LinearLayout draggedItem = (LinearLayout) event.getLocalState(); //dragged LinearLayout

            GridView targetItem = (GridView) v; /* How do i get this drop target as LinearLayout so that i can delete or swap data */

            switch (dragEvent)
            
                case DragEvent.ACTION_DRAG_LOCATION:
                    if(reset==false) 
                        dragPositionStart = event.getX();
                        reset= true;
                    

                    if(Math.abs(dragPositionStart - event.getX())>=20) 
                        Log.i("Position close : ", Float.toString(dragPositionStart));

                        if(isPopupOpen) 
                            popupMenu.dismiss();
                            v.startDrag(data, dragShadow, itemView, 0);
                            Toast.makeText(mContext, "popup closed", Toast.LENGTH_SHORT).show();
                            isPopupOpen = false;
                        

                        reset = false;
                    

                    break;

                case DragEvent.ACTION_DROP:



                    Toast.makeText(mContext, "drop" + Integer.toString(targetItem.getChildCount()), Toast.LENGTH_SHORT).show();

                    break;


            

            return true;
        
    );

现在的问题是,当我在“Gridview”中放置 LinearLayout 时,我得到了放置目标“Gridview”。这个“LinearLayout”也是“Gridview”的子级。我希望放置目标是同一个“GridView”内的另一个“LinearLayout”。这样我就可以交换数据或重新排序。如下图。

【问题讨论】:

感谢您的回复。我解决了同时使用 OnTouchListner 和 OnDragListner 的问题。现在我将 gridview 作为放置目标元素。但是如何从其父 GridView 中获取目标 LinearLayout? 【参考方案1】:

据我了解,您想做两件事。 1)拖动后重新排序视图。 2)重新排序后更改视图类型。

对于问题 1,因为它是一个网格视图,听起来我们真的只想重新排序适配器中的数据,并可能更改数据以使其显示不同。但是我们需要弄清楚原始物品的位置和目标目的地位置。

我们可以扩展 GridView 来做到这一点:

public class DragAndDropGridView extends GridView 

    public void handleMove(int x, int y, int originalPosition) 


        Rect rect = new Rect();
        PushbackAdapter adapter = (PushbackAdapter) getAdapter();

        for (int visiblePosition = getFirstVisiblePosition(); visiblePosition <= getLastVisiblePosition(); visiblePosition++) 
            // TODO verify that there are no edge cases not covered by this

            View view = getChildAt(visiblePosition);
            int left = view.getLeft();
            int top = view.getTop();
            getChildVisibleRect(view, rect, null);
            rect.offsetTo(left, top);
            if (rect.contains(x, y)) 
                // yay the user tried drop the view at this location
                // determine if they wanted to drop it here or after this side
                int centerX = rect.centerX();
                if (x <= centerX) 
                    // we want to drop it here
                    adapter.move(originalPosition, visiblePosition);
                    adapter.notifyDataSetInvalidated();
                    break;
                 else 
                    // we want to drop it behind
                    adapter.move(originalPosition, visiblePosition + 1);
                    adapter.notifyDataSetInvalidated();
                    break;
                
            

        
    
  

剩下的就是调用handleMoveMethod。我们在 ACTION_DROP 方法中执行此操作。

                 case DragEvent.ACTION_DROP:


                        handleMove((int)event.getX(), (int)event.getY(), getPositionForView(draggedItem));


                        Toast.makeText(mContext, "drop" + Integer.toString(targetItem.getChildCount()), Toast.LENGTH_SHORT).show();

                        break;

最后(问题 2)听起来您可能想要更改该位置的对象内容或它包含的视图类型。如果您需要,我建议使用 getItemViewType 和 getItemViewTypeCount 方法不同类型的视图。例如。大致如下:

    private static class PushbackAdapter extends ArrayAdapter 

    ArrayList<Object> mItems;

    public void move(int originalPosition, int targetPosition)
        // TODO verify that this move logic is correct
        Object item = mItems.remove(originalPosition);
        item.useLinearLayoutType(true);
        mItems.add(targetPosition, item);
    

    ...

    @Override
    public int getItemViewType(int i) 
        return mItems.get(i).isLeanearLayoutType()? 1 : 0;
    

这可能存在错误,所以请彻底测试

【讨论】:

【参考方案2】:

使用targetItem.pointToPosition(..)在Gridview中查找LinerLayout(拖动)的位置。

使用以下代码滑动 LinerLayout:

int i =targetItem.pointToPosition((int)event.getX(), (int)event.getY());
int j = Integer.parseInt(event.getClipData().getItemAt(0).getText().toString());
Collections.swap(targetItem, i, j);//swap Linerlayout
Log.i(TAG, "Swapped " + i+ " with " + j);

代码未经测试。我希望它对你有帮助。 :)

【讨论】:

以上是关于在 Android 中不会阻止拖放的不显眼的弹出窗口的主要内容,如果未能解决你的问题,请参考以下文章

百度统计 可以统计页面上的JS的弹出窗的打开次数吗? 怎么实现?

如何在 android studio 的弹出窗口内添加滚动的 listView?

修复Extjs5.1.4的弹出窗(window)BUG

DuiVision开发教程(18)-弹出窗

Android学习笔记二十之Toast吐司Notification通知PopupWindow弹出窗

解决selenium自动化上传图片或文件出现windows窗口问题