首页 文章

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

提问于
浏览
176

当使用导航抽屉时,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以重新显示导航抽屉图像的任何建议?


解决方案

汤姆的建议对我有用 . 这是我做的:

MainActivity

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

在准备新片段以替换其他片段时,我将DrawerToggle _988935设置为:

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)
}

在LowerLevelFragments中

在片段中,我修改了 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;
        … 
    }

12 回答

  • 2

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

    我认为你必须手动实现后退功能:当用户按下时,你有代码弹出堆栈(例如在 Activity::onBackPressed 覆盖中) . 所以,无论你做什么,你都可以扭转 setDrawerIndicatorEnabled .

  • 0

    这很简单,1-2-3 .

    如果你想实现:

    1) Drawer Indicator - 当后堆栈中没有碎片或抽屉打开时

    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行指标行为的其他提示,请参阅Creating a Navigation Drawer on Android Developers .

  • 1

    我用过下一件事:

    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);
                    }
                }
            });
    
  • 12

    如果您的向上操作栏按钮不起作用,请不要忘记添加监听器:

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

    我在使用主页按钮实现抽屉导航时遇到了一些麻烦,除了动作按钮外,一切都正常 .

  • 1

    尝试根据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);
        }
    }
    
  • 28

    FOLLOW UP

    @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);
        }
    }
    

    EDIT

    关于@JJD的问题 .

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

    在我的一个应用程序中,我还需要在按下后退按钮时处理向上插入符的行为 . 这可以通过覆盖 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 ,这在我的情况下是必需的,否则我有时候会有奇怪的插入符号 .

  • 7

    我为托管活动创建了一个界面来更新汉堡包菜单的视图状态 . 对于顶级片段,我将切换设置为 true ,对于我想要显示向上的片段<arrow,我将切换设置为 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);
        }
    
    }
    
  • 10

    这个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);
            }
    
        }
    
  • 1

    逻辑清晰 . 如果片段后栈是清除的,则显示后退按钮 . 如果碎片堆栈不清楚,则显示材料汉堡包动画 .

    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;
    }
    
  • 14

    如果您看一下GMAIL应用程序并来这里搜索carret / compleance图标..

    我会请你这样做,上述答案都不清楚 . 我能够修改接受的答案 .

    • NavigationDrawer - > Listview包含子碎片 .

    • 子碎片将像这样列出

    • firstFragment == position 0 --->这将有subfragments - > fragment

    • secondFragment

    • thirdFragment等向前....

    在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

  • 2

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

  • 83

    IMO,在riwnodennyk 's or Tom'解决方案中使用onNavigateUp()(如图所示here)更清洁,似乎更好用 . 只需用以下代码替换onOptionsItemSelected代码:

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

相关问题