【问题标题】:AppCompat v7 Toolbar Up/Back Arrow Not WorkingAppCompat v7 工具栏上/后箭头不起作用
【发布时间】:2015-01-06 05:59:34
【问题描述】:

我在一个活动中有两个片段。当片段 A 显示时,我希望导航抽屉汉堡图标显示并且导航抽屉工作。当片段 B 显示时,我希望显示后退箭头,并在单击它时进行向上导航。但是,除非导航抽屉打开,否则我似乎无法让新的 AppCompat v7 工具栏在我的 ActionBarActivity 中显示向上箭头。

在我的活动中,对于我的 onCreate() 方法,我有...

toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
    setSupportActionBar(toolbar);
}
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);

然后我在 onPostCreate() 中调用 mDrawerToggle.syncState();

我尝试搜索如何以编程方式将工具栏图标触发到后退箭头,但没有任何效果。根据我收集到的信息,呼唤

getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);

我的片段应该改变图标,但事实并非如此。这可能是一个愚蠢的问题,但我做错了什么?

【问题讨论】:

    标签: android android-fragments android-actionbar android-actionbaractivity android-toolbar


    【解决方案1】:

    从我在 v7 ActionBarDrawerToggle 的源代码中看到的,您可以在不打开抽屉的情况下将图标设置为不同的状态。

     private enum ActionDrawableState{
            BURGER, ARROW
        }
        private static void toggleActionBarIcon(ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate){
            if(animate) {
                float start = state == ActionDrawableState.BURGER ? 0f : 1.0f;
                float end = Math.abs(start - 1);
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
                    offsetAnimator.setDuration(300);
                    offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
                    offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            float offset = (Float) animation.getAnimatedValue();
                            toggle.onDrawerSlide(null, offset);
                        }
                    });
                   offsetAnimator.start();
                }else{
                    //do the same with nine-old-androids lib :)
                }
            }else{
                if(state == ActionDrawableState.BURGER){
                    toggle.onDrawerClosed(null);
                }else{
                    toggle.onDrawerOpened(null);
                }
            }
        }
    

    Burger 和 Arrow 之间的变形取决于 0f1.0f 之间的值,基本上这些是抽屉传递给 ActionBarDrawerToggle 的值。

    我使用ValueAnimator 为该范围内的值设置动画,即模仿抽屉切换。

    null 参数是安全的,因为ActionBarDrawerToggle 根本不关心抽屉视图。 确保你看看新的插值器来完全按照材料设计指南的书来制作动画:

    fast_out_linear_in  
    fast_out_slow_in
    

    另一种方法是通过反射访问ActionBarDrawermSlider 私有字段并调用setPosition(float position) 方法在Burger 和Arrow 之间切换。 mSlider 属于(扩展)DrawerArrowDrawable

    就个人而言,我总是尽量避免反思,只要没有其他方法可以做你的肮脏工作。

    【讨论】:

    • 这正是我想要的。谢谢!
    【解决方案2】:

    在我的例子中,图标是动画的: 我用过 ActionBarDrawerToggle v7。

    主活动:

        Toolbar toolbar = (Toolbar) findViewById(R.id.tool1);
    
        setSupportActionBar(toolbar);
        toolbar.setTitle("ToolBar Demo");
        toolbar.setLogo(R.drawable.ic_launcher);
    
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
    
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar,
                R.string.open_navigation_drawer,
                R.string.close_navigation_drawer) {
    
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                // TODO Auto-generated method stub
                super.onDrawerSlide(drawerView, slideOffset);
            }
    
            /** Called when a drawer has settled in a completely closed state. */
            @Override
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getSupportActionBar().setTitle("hello");
            }
    
            /** Called when a drawer has settled in a completely open state. */
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getSupportActionBar().setTitle("hi");
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    
    
    
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) { // <---- added
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    protected void onPostCreate(Bundle savedInstanceState) { // <---- added
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState(); // important statetment for drawer to
                                    // identify
                                    // its state
    }
    
    @Override
    public void onConfigurationChanged(Configuration newConfig) { // <---- added
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
    
    @Override
    public void onBackPressed() {
        if (mDrawerLayout.isDrawerOpen(Gravity.START | Gravity.LEFT)) { // <----
                                                                        // added
            mDrawerLayout.closeDrawers();
            return;
        }
        super.onBackPressed();
    }
    

    【讨论】:

      【解决方案3】:
      getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
              @Override
              public void onBackStackChanged() {
                  int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
                  if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
                      getSupportActionBar().setHomeButtonEnabled(true);
                      getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                  } else {
                      getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                      getSupportActionBar().setHomeButtonEnabled(false);
                  }
              }
      
          });
      

      之后……

      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
              case android.R.id.home:
                  getSupportFragmentManager().popBackStack();
                  return true;
           ....
       }
      

      【讨论】:

        【解决方案4】:

        随着支持库更新到 23.0.0,有更好的方法来播放抽屉箭头动画。所以我要改进@Nikola 的答案。代码如下:

        public static void playDrawerToggleAnim(final DrawerArrowDrawable d) {
            float start = d.getProgress();
            float end = Math.abs(start - 1);
            ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
            offsetAnimator.setDuration(300);
            offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
            offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float offset = (Float) animation.getAnimatedValue();
                    d.setProgress(offset);
                }
            });
            offsetAnimator.start();
        }
        

        并随时通过以下方式调用它:

        playDrawerToggleAnim((DrawerArrowDrawable) toolbar.getNavigationIcon());
        

        【讨论】:

          猜你喜欢
          • 2014-12-25
          • 2014-12-22
          • 2014-12-14
          • 2015-01-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-19
          相关资源
          最近更新 更多