导航抽屉在配置更改时关闭
Navigation drawer closes on configuration change
在我的片段中,我以编程方式将片段添加到导航抽屉中,然后从右侧打开抽屉。请注意,我无法直接访问 DrawerLayout 的 xml 文件,因此需要一个编程解决方案。抽屉从右侧打开并正确关闭,我保留抽屉的 open/close 状态,并在配置基于该状态更改后打开它。
问题是,在配置更改时,抽屉关闭(我可以看到抽屉动画到关闭状态),即使我根据 savedInstanceState 布尔值恢复其 open/close 状态。我在 DrawerLayout.class
中的所有 closeDrawer
方法中放置了一个调试器,但它们没有被命中。
更新:我想我知道问题出在哪里,但我不确定如何在不扩展 DrawerLayout 本身的情况下解决这个问题。在 DrawerLayout#onRestoreInstanceState
中调用的 DrawerLayout#findDrawerWithGravity
在我的例子中返回 null。
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_DRAWER_OPEN,
getDrawerLayout() == null ? false : getDrawerLayout().isDrawerOpen(Gravity.RIGHT));
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
isDrawerOpen = savedInstanceState.getBoolean(STATE_DRAWER_OPEN);
}
private void setDrawer() //this is called in onCreate
{
DrawerLayout drawer = getActivity().findViewById(R.id.drawer_layout);
if (drawer == null)
drawer = getDrawerLayout();
View existing = drawer.findViewById(R.id.m_drawer_container);
if (existing != null)
drawer.removeView(existing);
drawer.setFocusableInTouchMode(false);
drawer.addDrawerListener(this);
FrameLayout fragmentContainer = new FrameLayout(getActivity());
fragmentContainer.setId(R.id.m_drawer_container);
final DrawerLayout.LayoutParams layoutParams = new DrawerLayout.LayoutParams(
getResources().getDimensionPixelSize(R.dimen.m_drawer_max_width),
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.RIGHT);
drawer.addView(fragmentContainer, layoutParams);
FragmentManager fragmentManager = getFragmentManager();
MyDrawerFragment mDrawerFragment = null;
Fragment frag = fragmentManager.findFragmentByTag(TAG_DRAWER_FRAGMENT);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (frag != null && frag.isAdded())
fragmentTransaction.remove(frag);
mDrawerFragment = MyDrawerFragment.newInstance(myArgs);
fragmentTransaction.add(R.id.m_drawer_container, drawerFragment, TAG_DRAWER_FRAGMENT);
fragmentTransaction.commitAllowingStateLoss();
if (isDrawerOpen)
drawer.openDrawer(Gravity.RIGHT);
}
事实证明,答案是调用 drawer.openDrawer(Gravity.RIGHT, false);
以在从配置更改恢复时禁用动画。原因是调用 drawer.openDrawer(Gravity.RIGHT)
时默认将动画设置为 true,深入研究该方法最终会导致 DrawerLayout.java
中的这段代码,从而导致宽度计算不正确,从而导致抽屉 "hidden":
DrawerLayout.java
else if (animate) {
lp.openState |= LayoutParams.FLAG_IS_OPENING;
if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
} else {
mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
drawerView.getTop());
}
解决方案是在从配置更改恢复时将 animate 设置为 false。
if (isDrawerOpen && isRestoreFromConfigChange)
drawer.openDrawer(Gravity.RIGHT, false);
在我的片段中,我以编程方式将片段添加到导航抽屉中,然后从右侧打开抽屉。请注意,我无法直接访问 DrawerLayout 的 xml 文件,因此需要一个编程解决方案。抽屉从右侧打开并正确关闭,我保留抽屉的 open/close 状态,并在配置基于该状态更改后打开它。
问题是,在配置更改时,抽屉关闭(我可以看到抽屉动画到关闭状态),即使我根据 savedInstanceState 布尔值恢复其 open/close 状态。我在 DrawerLayout.class
中的所有 closeDrawer
方法中放置了一个调试器,但它们没有被命中。
更新:我想我知道问题出在哪里,但我不确定如何在不扩展 DrawerLayout 本身的情况下解决这个问题。在 DrawerLayout#onRestoreInstanceState
中调用的 DrawerLayout#findDrawerWithGravity
在我的例子中返回 null。
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_DRAWER_OPEN,
getDrawerLayout() == null ? false : getDrawerLayout().isDrawerOpen(Gravity.RIGHT));
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
isDrawerOpen = savedInstanceState.getBoolean(STATE_DRAWER_OPEN);
}
private void setDrawer() //this is called in onCreate
{
DrawerLayout drawer = getActivity().findViewById(R.id.drawer_layout);
if (drawer == null)
drawer = getDrawerLayout();
View existing = drawer.findViewById(R.id.m_drawer_container);
if (existing != null)
drawer.removeView(existing);
drawer.setFocusableInTouchMode(false);
drawer.addDrawerListener(this);
FrameLayout fragmentContainer = new FrameLayout(getActivity());
fragmentContainer.setId(R.id.m_drawer_container);
final DrawerLayout.LayoutParams layoutParams = new DrawerLayout.LayoutParams(
getResources().getDimensionPixelSize(R.dimen.m_drawer_max_width),
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.RIGHT);
drawer.addView(fragmentContainer, layoutParams);
FragmentManager fragmentManager = getFragmentManager();
MyDrawerFragment mDrawerFragment = null;
Fragment frag = fragmentManager.findFragmentByTag(TAG_DRAWER_FRAGMENT);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (frag != null && frag.isAdded())
fragmentTransaction.remove(frag);
mDrawerFragment = MyDrawerFragment.newInstance(myArgs);
fragmentTransaction.add(R.id.m_drawer_container, drawerFragment, TAG_DRAWER_FRAGMENT);
fragmentTransaction.commitAllowingStateLoss();
if (isDrawerOpen)
drawer.openDrawer(Gravity.RIGHT);
}
事实证明,答案是调用 drawer.openDrawer(Gravity.RIGHT, false);
以在从配置更改恢复时禁用动画。原因是调用 drawer.openDrawer(Gravity.RIGHT)
时默认将动画设置为 true,深入研究该方法最终会导致 DrawerLayout.java
中的这段代码,从而导致宽度计算不正确,从而导致抽屉 "hidden":
DrawerLayout.java
else if (animate) {
lp.openState |= LayoutParams.FLAG_IS_OPENING;
if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
} else {
mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
drawerView.getTop());
}
解决方案是在从配置更改恢复时将 animate 设置为 false。
if (isDrawerOpen && isRestoreFromConfigChange)
drawer.openDrawer(Gravity.RIGHT, false);