Navigation Drawerを使用する場合、Android開発者は、ActionBarで「Navigation Drawerに表示される画面のみに実際にNavigation Drawer画像が必要」および「他のすべての画面には従来のアップカラットがある」ことを推奨しています」
詳細はこちらをご覧ください: http://youtu.be/F5COhlbpIbY
フラグメントの複数のレベルを制御するために1つのアクティビティを使用しており、ナビゲーションドロワーイメージを表示してすべてのレベルで機能させることができます。
下位レベルのフラグメントを作成するときは、ActionBarDrawerToggle
setDrawerIndicatorEnabled(false)
を呼び出してナビゲーションドロワーの画像を非表示にし、Upキャレットを表示できます。
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)
}
フラグメントでは、onCreate
とonOptionsItemSelected
を次のように変更しました。
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()
を呼び出して、階層を1レベル上に移動し、ナビゲーションドロワーイメージを表示します。
@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;
…
}
下位レベルのフラグメントを実装するには、新しいアクティビティで下位レベルのフラグメントを実装するのではなく、既存のフラグメントを置き換えることを書きました。
その後、手動でバック機能を実装する必要があると思います:ユーザーが押し戻すと、スタックをポップするコードがあります(たとえば、Activity::onBackPressed
オーバーライドで)。そのため、どこで実行する場合でも、setDrawerIndicatorEnabled
を逆にすることができます。
1-2-3のように簡単です。
達成したい場合:
1)引き出しインジケータ-バックスタックにフラグメントがない場合、または引き出しが開いている場合
2)Arrow-一部のフラグメントがバックスタックにある場合
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);
}
}
追伸3行インジケーターの動作に関するその他のヒントについては、 Android Developersでのナビゲーションドロワーの作成 を参照してください。
私は次のものを使用しました:
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();
}
});
ホームボタンを使用したドロワーナビゲーションの実装に問題があり、アクションボタン以外はすべて機能しました。
DrawerToggleの状態に応じて、MainActivityでホームアイテムの選択を処理してみてください。この方法では、すべてのフラグメントに同じコードを追加する必要はありません。
@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の質問に対して。
フラグメントはアクティビティで保持/管理されます。上記のコードはそのアクティビティで1回記述されていますが、onOptionsItemSelected
のアップキャレットのみを処理します。
私のアプリの1つでは、戻るボタンが押されたときのアップキャレットの動作も処理する必要がありました。これは、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);
}
}
};
onOptionsItemSelected
とonBackPressed
の間のコードの重複に注意してください。これは、メソッドを作成し、両方の場所でそのメソッドを呼び出すことで回避できます。
また、私の場合は必須だったexecutePendingTransactions
をさらに2回追加したことに注意してください。さもなければ、アップキャレットの奇妙な動作があったこともあります。
ホスティングアクティビティ用のインターフェイスを作成して、ハンバーガーメニューの表示状態を更新しました。トップレベルのフラグメントの場合はトグルを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);
}
}
この answer は機能していましたが、少し問題がありました。 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;
}
この小さな例を見ることができます! https://github.com/oskarko/NavDrawerExample
GMAILアプリを見て、ここに来てキャレット/アフォーダンスのアイコンを検索してください。
これを行うようお願いしますが、上記の答えはどれも明確ではありませんでした。私は受け入れられた答えを修正することができました。
NavigationDrawer-> Listviewにはサブフラグメントが含まれています。
サブフラグメントはこのようにリストされます
firstFragment == position 0 --->これはサブフラグメントを持つ->フラグメント
FirstFragmentには、他のフラグメントがあります。
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;
}
OnBackPressed Drawerアクティビティメソッドで、ドロワートグルをtrueに設定して、ナビゲーションリストアイコンを再度有効にします。
ありがとう、Pusp
IMO、riwnodennykまたはTomのソリューションでonNavigateUp()( here に示すように)を使用すると、よりクリーンになり、より適切に動作するようです。 onOptionsItemSelectedコードを次のように置き換えます。
@Override
public boolean onSupportNavigateUp() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handle up navigation
return true;
} else {
return super.onSupportNavigateUp();
}
}