Панель инструментов AppCompat v7 Up/Back Arrow не работает

У меня есть два фрагмента в активности. Когда отображается фрагмент A, я хочу, чтобы значок гамбургера навигационного ящика показывался, и ящик навигации работал. Когда фрагмент B показывает, я хочу, чтобы стрелка назад показывалась, и когда она щелкнула, сделайте навигацию вверх. Тем не менее, я не могу заставить новую панель инструментов AppCompat v7 показывать стрелку вверх вообще в моей ActionBarActivity, если ядро ​​nav открыто.

В моей работе для моего метода 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);

И затем я вызываю mDrawerToggle.syncState(); в свой onPostCreate()

Я пробовал поиск того, как программно запускать значок панели инструментов на стрелку назад, но ничего не сработало. Из того, что я собрал, позвонив

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

из моего фрагмента следует изменить значок, но это не так. Это может быть глупый вопрос, но что я делаю неправильно?

Ответ 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 зависит от значений между 0f и 1.0f, в основном это значения, которые ящик передает в ActionBarDrawerToggle.

Я использовал ValueAnimator для анимации значений в этом диапазоне, т.е. имитации переключения ящика.

null аргументы безопасны, потому что ActionBarDrawerToggle вообще не интересует представления ящиков. Удостоверьтесь, что вы взгляните на новые интерполяторы, чтобы сделать анимацию полностью по книге рекомендаций по дизайну материалов:

fast_out_linear_in  
fast_out_slow_in

Другим подходом является доступ к частному полю mSlider метода ActionBarDrawer через отражение и вызов setPosition(float position) для переключения между Burger и Arrow. mSlider имеет тип (продолжается) DrawerArrowDrawable.

Лично я всегда стараюсь избегать размышлений, пока нет другого способа сделать вашу грязную работу.

Ответ 2

В качестве поддержки библиотеки, обновленной до 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());

Ответ 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

В моем случае значок оживляет: Я использовал ActionBarDrawerToggle v7.

MainActivity:

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