如何在多片段活动中处理 onContextItemSelected?
我目前正在尝试调整我的应用程序以使用“Android v4 的兼容性库”,甚至为 Android 1.6 用户提供使用片段的好处。
上下文菜单的实现似乎很棘手:
- 应用程序的主要活动 正在扩展 FragmentActivity 班级。
- 这些片段均基于一个 扩展 Fragment 类的类。
- 片段类正在调用 registerForContextMenu() 在其 onCreateView() 方法中并覆盖这些方法 onCreateContextMenu() 和 onContextItemSelected()。
对于onCreateContextMenu(),这非常有效。上下文菜单是从资源文件中扩充的,并根据所选项目(基于 listView...即使片段不是 ListFragment)稍加修改。
选择上下文菜单条目时会出现此问题。 从第一个添加的片段开始,对所有当前存在的片段调用 onContextItemSelected() 。
就我而言,片段用于显示文件夹结构的内容。当打开子文件夹片段的上下文菜单并选择菜单项时,首先在上层调用 onContextItemSelected() (取决于此时允许/可见的片段数量)。
现在,我使用活动级别的字段来解决方法,该字段保存调用其 onCreateContextMenu() 的最后一个片段的标签。这样,当存储的标签与 getTag() 不同时,我可以在 onContextItemSelected() 的开头调用“return super.onContextItemSelected(item)”。 但这种方法对我来说看起来有点肮脏。
为什么在所有片段上调用 onContextItemSelected() ?而不仅仅是调用 onCreateContextMenu() 的那个?
处理这个问题最优雅的方法是什么?
I'm currently trying to adapt my application to use the "Compatibility Libraries for Android v4" to provide the benefits of the usage of fragments even to Android 1.6 users.
The implementation of a context menu seems to be tricky:
- The main activity of the application
is extending the FragmentActivity
class. - The fragments are all based on one
class which extends the Fragment class. - The fragment class is calling
registerForContextMenu() in its onCreateView() method and overrides the methods
onCreateContextMenu() and onContextItemSelected().
For onCreateContextMenu() this works pretty well. The context menu is inflated from a resource file and slightly modified based on the selected item (which is based on a listView... even if the fragment is not an ListFragment).
The problem occurs when a context menu entry is selected.
onContextItemSelected() is called for all currently existing fragments starting with the first added one.
In my case the fragments are used to show the content of a folder structure. When the context menu of a subfolder fragment is opened and a menu item is selected, onContextItemSelected() is first called on the upper levels (depending on how many fragments are allowed/visible in this moment).
Right now, I use a workaround by a field on activity level which holds the tag of last fragment calling its onCreateContextMenu(). This way I can call "return super.onContextItemSelected(item)" in the begin of onContextItemSelected() when the stored tag is not the same as getTag().
But this approach looks a bit dirty to me.
Why is onContextItemSelected() called on all fragments? and not just one the one that was calling onCreateContextMenu()?
What is the most elegant way to handle this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
即使您找到了解决方法,我也会发布答案,因为我刚刚处理了类似的问题。当您扩充特定片段的上下文菜单时,请为每个菜单项分配一个该片段唯一的 groupId。然后在“onContextItemSelected”中测试 groupId。例如:
这样,所有片段仍将收到对“onContextItemSelected”的调用,但只有正确的片段才会响应,从而避免了编写活动级代码的需要。我认为即使您没有使用“menu.add(...)”,该技术的修改版本也可以工作
I'll post an answer even though you found a workaround because I just dealt with a similar issue. When you inflate the context menu for a specific fragment, assign each menu item a groupId that is unique to the fragment. Then test for the groupId in 'onContextItemSelected.' For Example:
This way all of your fragments will still receive calls to 'onContextItemSelected,' but only the correct one will respond, thus avoiding the need to write activity-level code. I assume a modified version of this technique could work even though you aren't using 'menu.add(...)'
另一种解决方案:
基于 Jake Wharton 的此补丁。
Another one solution:
Based upon this patch from Jake Wharton.
我喜欢 Sergei G 的简单解决方案(基于 Jake Wharton 修复),但相反,因为它更容易添加到多个片段:
之后,代码与之前相同。
I liked the simple solution by Sergei G (based on Jake Wharton fix), but inverted because it is easier to add to several fragments:
After that, the code same as it was before.
我找到了一个非常简单的解决方案。由于每次创建 ContextMenu 时都会调用 onCreateContextMenu(),因此我将布尔变量设置为 true。
我唯一要做的另一件事就是请求该变量 OnContextItemSelected()
就是这样。
I found out a very easy solution. As onCreateContextMenu() is called every time the ContextMenu is created I set a boolean variable to true.
The only other thing I have to do is ask for that variable OnContextItemSelected()
That's it.
我找到了一个替代方案。它不会改变我上面的问题,但它使它变得毫无意义。
我已从我的应用程序中完全删除了上下文菜单。相反,我捕获了对列表项的长按,并此时更改操作栏的可见按钮。
从用户的角度来看,这更像是平板电脑的上下文菜单。
在向后兼容的应用程序中,操作栏不存在。因此,我决定为 Honeycomb 之前的设备构建自己的(顶部的工具栏)。
如果您想继续使用上下文菜单,我没有找到更好的解决方案作为我上面提到的解决方法。
I found an alternative. It does not change anything on my problem above, but it makes it pointless.
I have remove the context menu completely from my application. Instead I capture the longclick on a list item and change the visible buttons of the action bar in this moment.
From the user point of view this is much more tablet like as a context menu.
In backward compatible applications the actionbar does not exist. So I've decided to build my own (kind of toolbar on top) for the devices pre Honeycomb.
If you would like to stay with the context menu, I did not find a better solution as the workaround I've mentioned above.
如果您在片段中使用带有列表视图的适配器,这可能会有所帮助。
If you are using adapters with listviews in your fragment this might help.
在我的第一个片段中,我设置了所有菜单 id > 5000 所以,作为我拥有的第一个片段的 onContextItemSelected 的第一行代码
,将调用第二个片段。
In my first fragment, i have set all my menu id > 5000 so, as first line of code of onContextItemSelected of first fragment i have
and the second fragment will be invoked.
只需更改
为即可
,效果会很好!
Just change
to
and will work great!!!
恕我直言,我们可能只是检查目标视图是否是片段列表视图的子视图。它非常简单并且对我来说效果很好。我刚刚添加到所有片段:
if (getListView.getPositionForView(info.targetView) == -1)
从旧 API 迁移时返回 false
这是我的父片段之一的示例。这是 Scala,但我希望你有一个想法。
PS 如果您跟踪 onContextItemSelected(...) 的调用,您可能会注意到
super.onContextItemSelected(item)
始终返回false
。有效的 onContextItemSelected 在之后调用,而不是在之内调用。所以super.onContextItemSelected(item)
没有用,我用false
替换它。IMHO we may just check if target view is child of fragment listview. It is very simple and work for me well. I just added to all my fragments:
if (getListView.getPositionForView(info.targetView) == -1)
when migrate from older APIreturn false
This is example from one of my parent fragments. This is Scala, but I hope you got an idea.
P.S. If you trace calls of onContextItemSelected(...) you may notify that
super.onContextItemSelected(item)
return alwaysfalse
. Valid onContextItemSelected invoked AFTER, not WITHIN. Sosuper.onContextItemSelected(item)
is useless and I replaced it withfalse
.在改变的方法中返回true;返回 super.onContextItemSelected(item);在我的 onContextItemSelected() 重写中,一切都开始工作。
In the method changed return true; to return super.onContextItemSelected(item); in my onContextItemSelected() override and everything started working.
我找到了一个比暴露的更简单的解决方案:
I found an easier solution than the exposed: