使用片段时在 Android 导航抽屉图像和 Up 插入符号之间切换

当使用导航抽屉时,Android 开发人员建议在 ActionBar 中“只有那些在导航抽屉中显示的屏幕应该有导航抽屉图像”,并且“所有其他屏幕都有传统的向上克拉”

详情请参阅此处: http://youtu.be/F5COhlbpIbY

我使用一个活动来控制多个级别的片段,并可以获得导航抽屉图像显示和功能在所有级别。

在创建较低级别的片段时,我可以调用 ActionBarDrawerToggle setDrawerIndicatorEnabled(false)来隐藏导航抽屉图像并显示向上插入符号

LowerLevelFragment lowFrag = new LowerLevelFragment();


//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,
lowFrag, "lowerFrag").addToBackStack(null).commit();

我遇到的问题是,当我导航回到顶层片段的向上克拉仍然显示,而不是原来的导航抽屉图像。关于如何“刷新”顶层片段上的 ActionBar 以重新显示导航抽屉图像,有什么建议吗?


解决方案

汤姆的建议对我很有效,我是这么做的:

主要活动

此活动控制应用程序中的所有片段。

当准备新的片段替换其他片段时,我设置 DrawerToggle setDrawerIndicatorEnabled(false)如下:

LowerLevelFragment lowFrag = new LowerLevelFragment();


//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,
lowFrag).addToBackStack(null).commit();

接下来,在重写 onBackPressed时,我将 DrawerToggle 设置为 setDrawerIndicatorEnabled(true),如下所示:

@Override
public void onBackPressed() {
super.onBackPressed();
// turn on the Navigation Drawer image;
// this is called in the LowerLevelFragments
setDrawerIndicatorEnabled(true)
}

在低层碎片中

在这些片段中,我像这样修改了 onCreateonOptionsItemSelected:

onCreate中增加了 setHasOptionsMenu(true)以启用配置选项菜单。还设置 setDisplayHomeAsUpEnabled(true)以启用操作栏中的 < :

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// needed to indicate that the fragment would
// like to add items to the Options Menu
setHasOptionsMenu(true);
// update the actionbar to show the up carat/affordance
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}

然后在 onOptionsItemSelected中,只要按下 < ,它就从活动中调用 onBackPressed(),在层次结构中向上移动一级,并显示导航抽屉图像:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Get item selected and deal with it
switch (item.getItemId()) {
case android.R.id.home:
//called when the up affordance/carat in actionbar is pressed
getActivity().onBackPressed();
return true;
…
}
72368 次浏览

您已经写过,为了实现较低级别的片段,需要替换现有的片段,而不是在新活动中实现较低级别的片段。

我认为您必须手动实现后退功能: 当用户按下后退键时,您就有弹出堆栈的代码(例如,在 Activity::onBackPressed覆盖中)。所以,无论你在哪里,你都可以逆转 setDrawerIndicatorEnabled

根据 DrawerToggle 的状态,尝试在 MainActivity 中处理 Home 项选择。这样,您就不必向每个片段添加相同的代码。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch (item.getItemId()) {
// Handle home button in non-drawer mode
case android.R.id.home:
onBackPressed();
return true;


default:
return super.onOptionsItemSelected(item);
}
}

跟进

@ dzeikei 给出的解决方案非常简洁,但是当使用片段时,它可以被扩展,以便在回退堆栈为空时自动处理设置折叠指示符。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch (item.getItemId()) {
// Handle home button in non-drawer mode
case android.R.id.home:
// Use getSupportFragmentManager() to support older devices
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.popBackStack();
// Make sure transactions are finished before reading backstack count
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
return true;


default:
return super.onOptionsItemSelected(item);
}
}

剪辑

关于@JJD 的问题。

片段在活动中保存/管理。上面的代码在该活动中编写一次,但是只处理 onOptionsItemSelected的向上插入符号。

在我的一个应用程序中,我还需要处理按下后退按钮时向上插入符号的行为。这可以通过覆盖 onBackPressed来处理。

@Override
public void onBackPressed() {
// Use getSupportFragmentManager() to support older devices
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
super.onBackPressed();
} else {
fragmentManager.executePendingTransactions();
fragmentManager.popBackStack();
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
};

请注意 onOptionsItemSelectedonBackPressed之间的代码重复,这可以通过创建一个方法并在两个地方调用该方法来避免。

还要注意的是,我多加了两次 executePendingTransactions,这在我的情况下是必需的,否则我有时会出现向上插入符号的奇怪行为。

就像1-2-3一样简单。

如果你想达到以下目标:

1) 抽屉指示器-当没有碎片在后面的堆栈或抽屉被打开

2) -当一些碎片在后面的堆栈

private FragmentManager.OnBackStackChangedListener
mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
syncActionBarArrowState();
}
};


@Override
protected void onCreate(Bundle savedInstanceState) {
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_navigation_drawer,
0,
0
) {


public void onDrawerClosed(View view) {
syncActionBarArrowState();
}


public void onDrawerOpened(View drawerView) {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
};


mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
}


@Override
protected void onDestroy() {
getSupportFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener);
super.onDestroy();
}


private void syncActionBarArrowState() {
int backStackEntryCount =
getSupportFragmentManager().getBackStackEntryCount();
mDrawerToggle.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}

3)两个指示器根据它们的形状行动

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
} else if (item.getItemId() == android.R.id.home &&
getSupportFragmentManager().popBackStackImmediate()) {
return true;
} else {
return super.onOptionsItemSelected(item);
}
}

另外,请参阅 在 Android 开发人员中创建导航抽屉关于3行指示器行为的其他提示。

我为托管活动创建了一个界面来更新汉堡包菜单的视图状态。对于顶级片段,我将切换设置为 true,对于想要显示向上箭头的片段,我将切换设置为 false

public class SomeFragment extends Fragment {


public interface OnFragmentInteractionListener {
public void showDrawerToggle(boolean showDrawerToggle);
}


private OnFragmentInteractionListener mListener;


@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
this.mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
}
}


@Override
public void onResume() {
super.onResume();
mListener.showDrawerToggle(false);
}
}

然后在我的活动中..。

public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {


private ActionBarDrawerToggle mDrawerToggle;


public void showDrawerToggle(boolean showDrawerIndicator) {
mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
}


}

在 riwnodennyk 或 Tom 的解决方案中使用 onNavigateUp ()(如图所示的 给你)会更干净,而且似乎效果更好。只需将 onOptionsItemSelected 代码替换为:

@Override
public boolean onSupportNavigateUp() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handle up navigation
return true;
} else {
return super.onSupportNavigateUp();
}
}

这个 回答是工作,但有一个小问题。 getSupportActionBar().setDisplayHomeAsUpEnabled(false)没有被显式调用,它导致抽屉图标被隐藏,甚至当没有项目在回栈中,所以改变 setActionBarArrowDependingOnFragmentsBackStack()方法为我工作。

private void setActionBarArrowDependingOnFragmentsBackStack() {
int backStackEntryCount = getSupportFragmentManager()
.getBackStackEntryCount();
// If there are no items in the back stack
if (backStackEntryCount == 0) {
// Please make sure that UP CARAT is Hidden otherwise Drawer icon
// wont display
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
// Display the Drawer Icon
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else {
// Show the Up carat
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Hide the Drawer Icon
mDrawerToggle.setDrawerIndicatorEnabled(false);
}


}

逻辑很清楚。 显示返回按钮,如果片段返回堆栈是明确的。 如果片段堆栈不清晰,显示材料汉堡包-背动画。

getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
syncActionBarArrowState();
}
}
);




private void syncActionBarArrowState() {
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
mNavigationDrawerFragment.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}


//add these in Your NavigationDrawer fragment class


public void setDrawerIndicatorEnabled(boolean flag){
ActionBar actionBar = getActionBar();
if (!flag) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setHomeAsUpIndicator(getColoredArrow());
} else {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
mDrawerToggle.syncState();
getActivity().supportInvalidateOptionsMenu();
}


//download back button from this(https://www.google.com/design/icons/) website and add to your project


private Drawable getColoredArrow() {
Drawable arrowDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_arrow_back_black_24dp);
Drawable wrapped = DrawableCompat.wrap(arrowDrawable);


if (arrowDrawable != null && wrapped != null) {
// This should avoid tinting all the arrows
arrowDrawable.mutate();
DrawableCompat.setTint(wrapped, Color.GRAY);
}
return wrapped;
}

如果你看一下 GMAIL 应用程序,然后来这里搜索 carret/fordance 图标. 。

我会要求你这样做,以上的答案都不清楚。我可以修改已被接受的答案。

  • NavigationDrawer —— > Listview 包含子片段。


  • 子片段将像这样列出

  • FirstFragment = = 位置0——-> 这将有子片段—— > 片段

  • 第二段
  • 第三个碎片等等。

在第一个片段中还有其他片段。

在 DrawerActivity 上打这个电话

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
} else {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
});

而且是碎片

    setHasOptionsMenu(true);


@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Get item selected and deal with it
switch (item.getItemId()) {
case android.R.id.home:
//called when the up affordance/carat in actionbar is pressed
activity.onBackPressed();
return true;
}
return false;
}

在 OnBackPressDrawer 活动方法中,将折叠按钮设置为 true,以便再次启用导航列表图标。

谢谢, Pusp

接下来我用的是:

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() > 0){
mDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
});

如果你的向上操作栏按钮不工作,不要忘记添加侦听器:

// Navigation back icon listener
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});

我在实现一个带有主页按钮的抽屉导航时遇到了一些麻烦,除了操作按钮之外,所有东西都工作正常。

你可以看看这个小例子! Https://github.com/oskarko/navdrawerexample