我可以成功拦截从动作条
home键我的 NavigationDrawerFragment
,这是添加到我的 MainActivity
,像这样:
I can successfully intercept the ActionBar
home button from my NavigationDrawerFragment
, which is added to my MainActivity
, like so:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!loggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return super.onOptionsItemSelected(item);
}
不过,在我的 ComposeActivity
与 ComposeFragment
这不起作用。 onOptionsItemSelected
不叫段上。
However, in my ComposeActivity
with ComposeFragment
this does not work. onOptionsItemSelected
is not called on the fragment.
我已经调试了code和问题似乎回落到Android支持库的设计。看来,无论 FragmentActivity
和活动
有自己提述 FragmentManager
。
I have debugged the code and the issue seems to come down to the design of the Android support library. It appears that both FragmentActivity
and Activity
have their own references to a FragmentManager
.
FragmentActivity
首先检查是否活动
检查它的任何片段,这与一致之前,能够处理该事件文档:
FragmentActivity
first checks if Activity
can handle the event before checking any of its fragments, which is consistent with the docs:
/**
* Dispatch context and options menu to fragments.
*/
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (super.onMenuItemSelected(featureId, item)) {
return true;
}
switch (featureId) {
case Window.FEATURE_OPTIONS_PANEL:
return mFragments.dispatchOptionsItemSelected(item);
case Window.FEATURE_CONTEXT_MENU:
return mFragments.dispatchContextItemSelected(item);
default:
return false;
}
}
正如下面的代码片段,活动
处理home键作为最后的手段,检查,如果IT或任何其片段可以处理该事件之后。但这种参照 FragmentManager
不包含任何片段,这些片段都在 FragmentActivity
的经理。因此,该事件将获得由活动
类,如果 ActionBar.DISPLAY_HOME_AS_UP
设置吞噬。
As seen in the snippet below, Activity
handles the home button as a last resort, after checking if either it or any of its fragments can handle the event. But this reference to FragmentManager
does not contain any fragments, the fragments are in the FragmentActivity
's manager. Therefore the event will get swallowed by the Activity
class if ActionBar.DISPLAY_HOME_AS_UP
is set.
public boolean onMenuItemSelected(int featureId, MenuItem item) {
/* ... */
if (onOptionsItemSelected(item)) {
return true;
}
if (mFragments.dispatchOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == android.R.id.home && mActionBar != null &&
(mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
if (mParent == null) {
return onNavigateUp();
} else {
return mParent.onNavigateUpFromChild(this);
}
}
return false;
/* ... */
}
事实证明,我的 MainActivity
,是我的应用程序的根目录下,并使用导航抽屉里,没有这个标志设置等都没有吞下事件。但我的 ComposeActivity
有一个父活动,我需要这个标志被设置,因此无法拦截行动吧HOME键。
It turns out that my MainActivity
, being the root of my application and using a navigation drawer, did not have this flag set and so did not swallow the event. But my ComposeActivity
has a parent activity and I need this flag to be set so it is not possible to intercept the action bar home button.
要总结的问题:这是不可能拦截的点击 从片段与一个活动操作栏主页按钮 DISPLAY_HOME_AS_UP集。
To sum up the issue: It is not possible to intercept a click on the Action Bar home button from a fragment in an activity with with DISPLAY_HOME_AS_UP set.
因此,这是在支持库中的错误?它看起来并不像,如果我的目标更高Android版本和丢弃的支持库会发生。
So is this a bug in the support library? It doesn't look like it would occur if I targeted a later Android version and dropped the support library.
至于解决方法,我想我可以:
Regarding workarounds for this, I guess I could:
在我的 ComposeActivity
的 onOptionsItemSelected
我可以,如果他们手工传递事件给我的每个片段,看到调用super之前可以处理它。
覆盖onMenuItemSelected在 ComposeActivity
和做同样的事情。
In my ComposeActivity
's onOptionsItemSelected
I can manually pass the event to each of my fragments, seeing if they can handle it before calling super.
Override onMenuItemSelected in ComposeActivity
and do the same thing.
任何人都遇到过吗?我应该记录一个错误的地方?办法解决此问题的任何其他的想法?
Anybody encountered this before? Should I log a bug somewhere? Any other ideas of ways around this issue?
正如您所解释,由于该事件是如何分派在Android上的流动,似乎孩子片段永远不会拦截事件,因为它消耗的活动第一。
As you have explained, due to the flow of how the event is dispatched in Android, it seems the child fragment will never intercept the event because it's consumed by the Activity first.
这是一个解决办法,但我在做什么是传递事件之前,在活动进行处理。子片段
It's a workaround, but what I'm doing is passing the event to child fragments before is handled in the Activity.
在活动:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Due to a problem of not being able to intercept android.R.id.home in fragments,
// we start passing the event to the currently displayed fragment.
// REF: http://stackoverflow.com/questions/21938419/intercepting-actionbar-home-button-in-fragment
final Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.XXXXXXX);
if (currentFragment != null && currentFragment.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
case XXX:
...
return true;
case YYY:
...
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}