我目前正在尝试调整我的应用程序以使用“适用于Android v4的兼容性库”,以便为Android 1.6用户提供使用片段的好处。
上下文菜单的实现似乎很棘手:
对于 onCreateContextMenu(),这非常有效。上下文菜单从资源文件中膨胀,并根据所选项目进行略微修改(基于listView ...即使片段不是ListFragment)。
选择上下文菜单条目时会出现问题。 从第一个添加的片段开始,为所有当前存在的片段调用 onContextItemSelected()。
在我的例子中,片段用于显示文件夹结构的内容。当打开子文件夹片段的上下文菜单并选择菜单项时,首先在上层调用 onContextItemSelected()(取决于此时允许/可见的片段数)。 / p>
现在,我使用活动级别字段的变通方法,该字段包含调用其 onCreateContextMenu()的最后一个片段的标记。这样,当存储的标记与getTag()不同时,我可以在 onContextItemSelected()的开头调用“return super.onContextItemSelected(item)”。 但这种方法对我来说有点脏。
为什么在所有片段上调用onContextItemSelected()?而不仅仅是一个正在调用 onCreateContextMenu()的人?
处理此问题最优雅的方法是什么?
答案 0 :(得分:68)
即使您找到了解决方法,我也会发布一个答案,因为我刚刚处理了类似的问题。当您为特定片段的上下文菜单充气时,为每个菜单项分配一个对片段唯一的groupId。然后在'onContextItemSelected'中测试groupId。例如:
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_1, 0, R.string.src1);
menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_2, 0, R.string.src2);
}
public boolean onContextItemSelected(MenuItem item) {
//only this fragment's context menus have group ID of -1
if (item.getGroupId() == UNIQUE_FRAGMENT_GROUP_ID) {
switch(item.getItemId()) {
case MENU_OPTION_1: doSomething(); break;
case MENU_OPTION_2: doSomethingElse(); break;
}
}
这样你的所有片段仍将接收对'onContextItemSelected'的调用,但只有正确的片段才会响应,因此无需编写活动级代码。我假设即使您没有使用'menu.add(...)'
,此技术的修改版本也可以使用答案 1 :(得分:54)
另一个解决方案:
@Override
public boolean onContextItemSelected(MenuItem item) {
if (getUserVisibleHint()) {
// context menu logic
return true;
}
return false;
}
基于杰克沃顿的this patch。
答案 2 :(得分:8)
我喜欢Sergei G的简单解决方案(基于Jake Wharton修复),但因为更容易添加到几个片段而被倒置了:
public boolean onContextItemSelected(android.view.MenuItem item)
{
if( getUserVisibleHint() == false )
{
return false;
}
// The rest of your onConextItemSelect code
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
}
之后,代码与之前相同。
答案 3 :(得分:4)
我发现了一个非常简单的解决方案。每次创建ContextMenu时都会调用onCreateContextMenu(),我将布尔变量设置为true。
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.film_menu, menu);
bMenu=true;
}
我唯一需要做的就是要求变量OnContextItemSelected()
public boolean onContextItemSelected(MenuItem item) {
if (bMenu) {
bMenu=false;
if (item.getItemId() == R.id.filmProperties) {
///Your code
return true;
} else {
return super.onContextItemSelected(item);
}
} else {
return super.onContextItemSelected(item);
}
}
就是这样。
答案 4 :(得分:2)
我找到了另一种选择。它没有改变我上面的问题,但它使它毫无意义。
我已从我的应用程序中完全删除了上下文菜单。相反,我在列表项上捕获longclick并在此时更改操作栏的可见按钮。 从用户的角度来看,这更像平板电脑,就像上下文菜单一样。
在向后兼容的应用程序中,操作栏不存在。所以我决定为Honeycomb之前的设备构建我自己的(顶部的工具栏)。
如果您想继续使用上下文菜单,我找不到更好的解决方案作为我上面提到的解决方法。
答案 5 :(得分:1)
在我的第一个片段中,我设置了所有菜单ID> 5000所以,作为第一个片段的onContextItemSelected的第一行代码我有
if (item.getItemId() < 5000) return false;
将调用第二个片段。
答案 6 :(得分:1)
如果您在片段中使用带有listview的适配器,这可能会有所帮助。
public boolean onContextItemSelected(final MenuItem item) {
final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
//Check if the context menu call came from the list in this fragment (needed for support for multiple fragments in one screen)
if (info.targetView.getParent() != getView().findViewById(android.R.id.list))
return super.onContextItemSelected(item);
//Handle context menu item call
switch (item.getItemId()) {
...
}
}
答案 7 :(得分:0)
只需更改
@Override
public boolean onContextItemSelected(MenuItem item) {
return true;
}
到
@Override
public boolean onContextItemSelected(MenuItem item) {
return super.onContextItemSelected(item);
}
并且会很棒!!!
答案 8 :(得分:0)
恕我直言,我们可能只是检查目标视图是否是片段列表视图的子项。这很简单,对我很有帮助。我刚刚添加到我的所有片段:if (getListView.getPositionForView(info.targetView) == -1)
return false
从旧API迁移时
这是我的一个父片段的示例。这是Scala,但我希望你有个主意。
@Loggable
override def onContextItemSelected(menuItem: MenuItem): Boolean = {
for {
filterBlock <- TabContent.filterBlock
optionBlock <- TabContent.optionBlock
environmentBlock <- TabContent.environmentBlock
componentBlock <- TabContent.componentBlock
} yield menuItem.getMenuInfo match {
case info: AdapterContextMenuInfo =>
if (getListView.getPositionForView(info.targetView) == -1)
return false
TabContent.adapter.getItem(info.position) match {
case item: FilterBlock.Item =>
filterBlock.onContextItemSelected(menuItem, item)
case item: OptionBlock.Item =>
optionBlock.onContextItemSelected(menuItem, item)
case item: EnvironmentBlock.Item =>
environmentBlock.onContextItemSelected(menuItem, item)
case item: ComponentBlock.Item =>
componentBlock.onContextItemSelected(menuItem, item)
case item =>
log.debug("skip unknown context menu item " + info.targetView)
false
}
case info =>
log.fatal("unsupported menu info " + info)
false
}
} getOrElse false
P.S。如果您跟踪onContextItemSelected(...)的调用,您可以通知super.onContextItemSelected(item)
始终返回false
。有效的onContextItemSelected调用了 AFTER,而不是WITHIN 。因此super.onContextItemSelected(item)
无用,我将其替换为false
。
答案 9 :(得分:0)
我找到了比暴露更简单的解决方案:
public boolean onContextItemSelected(MenuItem item) {
ListView yourList = (ListView) (ListView) getView().findViewById(R.id.yourList);
if (!yourList.hasFocus())
return false;
switch(item.getItemId()) {
...
}
}
答案 10 :(得分:0)
在方法中更改返回true;返回super.onContextItemSelected(item);在我的onContextItemSelected()覆盖中,一切都开始工作。