Android GridView中的OnItemLongClick监听器在OnItemClick之后被调用

4

基本上,我想在用户在网格视图中短按或长按单元格时显示不同的上下文菜单。我的问题是,如果用户短按,则调用OnItemClick监听器,我看到调试器到达显示上下文菜单的代码,但它并没有从那里移动到onCreateContextMenu,而是转到了onItemLongClick。

我已经尝试使用布尔值来防止执行长点击代码,这确实可以防止执行该代码,但即使如此,onCreateContextMenu也根本没有被调用。

如果我删除onItemLongClick监听器,则短点击监听器将正常工作,并且上下文菜单将正确显示。

我知道其他人提出了类似的问题,但我仍然无法找到有效的解决方案。如果有人能解决这个问题或指导我正确的方向,请告诉我,非常感谢。即使是指引我正确方向的人也将获得奖励。

以下是监听器的简化版本:

        mTGrid.setOnItemClickListener(new OnItemClickListener() {
            //this listener should show the context menu for a short click on the gridview.
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                    mRequiredMenu = "standard";
                    parent.showContextMenuForChild(v);      

            }
        });

        mTGrid.setOnItemLongClickListener(new OnItemLongClickListener() {
            //this listener should show the context menu for a long click on the gridview.
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
                    mRequiredMenu = "options";
                        parent.showContextMenuForChild(v);      

            }
        });
5个回答

7
我了解您想在GridView项目的短按和长按上显示不同的上下文菜单。
首先,您只需要设置短按监听器,因为默认行为会自动在长按时显示上下文菜单。
接下来,在OnItemClickListener中设置一个布尔标志为true。默认值为false,适用于长按。
最后,在onCreateContextMenu()中检查是否为短按,并显示不同的上下文菜单(标准),并将标志设置为false。否则,让它显示默认的上下文菜单(选项)。
以下是一些代码,以示这个想法。
public class MainActivity extends Activity {

    private static final String[] arr = {"A", "B", "C", "D", "E", "F", "G", "H","I"};

    private GridView mTGrid;
    private boolean isShort;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mTGrid = (GridView) findViewById(R.id.gridView1);
        registerForContextMenu(mTGrid);

        mTGrid.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                isShort = true;
                openContextMenu(view);
            }
        });

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.cell, arr);
        mTGrid.setAdapter(adapter);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;

        if(isShort) {
            getMenuInflater().inflate(R.menu.context_standard, menu);
            menu.setHeaderTitle("Standard Menu for "+arr[info.position]);
            isShort = false;
        }
        else {
            getMenuInflater().inflate(R.menu.context_options, menu);
            menu.setHeaderTitle("Options Menu for "+arr[info.position]);
        }
    }   
}

示例应用: 您可以下载一个示例应用程序来查看其行为。 GridExample_eclipse_project


这完全解决了我的问题。我所要做的就是完全删除onItemLongClick监听器,然后只使用以下代码在onContextItemSelected()中获取所选单元格: - collusionbdbh
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); mSelectedCell = (myCellClass) info.targetView; - collusionbdbh

0

在绝望的情况下采取绝望的解决方案。

1.尝试使用布尔值,而不是在监听器内执行代码。

 mTGrid.setOnItemClickListener(new OnItemClickListener() {
        //this listener should show the context menu for a short click on the gridview.
        @Override
        public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                b=true     
        }
    });

    mTGrid.setOnItemLongClickListener(new OnItemLongClickListener() {
        //this listener should show the context menu for a long click on the gridview.
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
                b=false      
        }
    });
if(b)
{
     mRequiredMenu = "standard";
     parent.showContextMenuForChild(v);  
}
else
{
    mRequiredMenu = "options";
    parent.showContextMenuForChild(v);
}

检查您的布局中是否同时设置了可点击和长按属性为“true”。


“!”不起作用,因为代码在监听器之外,只有在设置监听器时才会执行,而不是在实际执行时执行。我的布局是动态设置的,当布局创建时,我已经在代码中设置了这些属性。无论如何,还是谢谢。 - collusionbdbh

0
mTGrid.setOnItemClickListener(new OnItemClickListener() {
            //this listener should show the context menu for a short click on the gridview.
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                     clickFlag=true;   
                     mRequiredMenu = "standard";                     

            }
        });

        mTGrid.setOnItemLongClickListener(new OnItemLongClickListener() {
            //this listener should show the context menu for a long click on the gridview.
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
                     clickFlag=false;
                     mRequiredMenu = "options";                  
            }
        });

if(clickFlag){        
    if(mRequiredMenu.equals("standard");{
        //just click event
        parent.showContextMenuForChild(v);
    }else{}
}else{
   if(mRequiredMenu.equals("options");{
        //just Long click event
        parent.showContextMenuForChild(v);
    }else{} 

}

显然不起作用。当代码到达时,clickFlag从未被修改过。 - njzk2

0

OnItemLongClickListener 会被触发,因为显示 ListView 的上下文菜单将尝试通过该监听器来实现。以下是来自 AbsListView 的代码:

@Override
public boolean showContextMenuForChild(View originalView) {
    final int longPressPosition = getPositionForView(originalView);
    if (longPressPosition >= 0) {
        final long longPressId = mAdapter.getItemId(longPressPosition);
        boolean handled = false;

        if (mOnItemLongClickListener != null) {
            handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, originalView,
                    longPressPosition, longPressId);
        }
        if (!handled) {
            mContextMenuInfo = createContextMenuInfo(
                    getChildAt(longPressPosition - mFirstPosition),
                    longPressPosition, longPressId);
            handled = super.showContextMenuForChild(originalView);
        }

        return handled;
    }
    return false;
}

从这里我们可以看到,如果mOnItemLongClickListener.onItemLongClick返回true,则表示该调用已处理并且该方法退出。如果它返回false,则尝试创建上下文菜单。
因此,您需要修改onItemLongClick中的返回语句(您的代码没有显示),以便在实际长按时返回true,而在仅单击时返回false
mTGrid.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {

        mRequiredMenu = "standard";
        mItemClicked = true;
        parent.showContextMenuForChild(v);
    }
});

mTGrid.setOnItemLongClickListener(new OnItemLongClickListener() {

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {

        if(mItemClicked) {
            mItemClicked = false;
            return false;
        }

        mRequiredMenu = "options";
        parent.showContextMenuForChild(v);
        return true;
    }
});

我尝试了这个,但出现了一些奇怪的行为,onItemLongClick被反复调用,似乎没有尽头,看起来它可能会为我的网格视图中的每个单元格调用一次。我绝对不明白它在做什么。 - collusionbdbh

0

您可以覆盖调度事件监听器,该监听器负责长按处理


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