панель дій вгору навігація з фрагментами


88

У мене є вкладки ActionBar / ViewPager макет з три вкладки каже A , B і C . На вкладці C вкладці (фрагмент), я додаю ще один фрагмент скаже фрагмент D . з

 DFragment f= new DFragment();
 ft.add(android.R.id.content, f, "");
 ft.remove(CFragment.this);
 ft.addToBackStack(null);
 ft.commit();

Я модифікую панель дій у DFragment's onResume, щоб додати кнопку:

ActionBar ab = getActivity().getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);

Тепер у DFragment, коли я натискаю апаратну (телефонну) кнопку Назад, я повертаюся до початкового макета з вкладками (ABC) із вибраним CFragment. Як я можу досягти цієї функції за допомогою кнопки вгору на панелі дій?


Відповіді:


185

Впровадьте OnBackStackChangedListenerта додайте цей код у свою діяльність з фрагментів.

@Override
public void onCreate(Bundle savedInstanceState) {
    //Listen for changes in the back stack
    getSupportFragmentManager().addOnBackStackChangedListener(this);
    //Handle when activity is recreated like on orientation Change
    shouldDisplayHomeUp();
}

@Override
public void onBackStackChanged() {
    shouldDisplayHomeUp();
}

public void shouldDisplayHomeUp(){
   //Enable Up button only  if there are entries in the back stack
   boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
   getSupportActionBar().setDisplayHomeAsUpEnabled(canGoBack);
}

@Override
public boolean onSupportNavigateUp() {
    //This method is called when the up button is pressed. Just the pop back stack.
    getSupportFragmentManager().popBackStack();
    return true;
}

20
Про onSupportNavigateUp(), "Метод не замінює метод із його суперкласу".
— Фред

10
Якщо у вас вже є a onOptionsItemSelected, можна також перевірити itemId android.R.id.homeзамість додавання onSupportNavigateUp.
— domsom

1
Якщо версія API> = 14, використовуйте onNavigateUp замість onSupportNavigateUp @Override public boolean onNavigateUp () {// Цей метод викликається при натисканні кнопки вгору. Просто поп-стек. getFragmentManager (). popBackStack (); повернути істинно; }
— Теясві Хегде

1
Чи має бути вставний символ, який відображається поруч із піктограмою вашого додатка в ActionBar? Я не бачу такої, коли реалізую цей код. Я можу лише натиснути на піктограму, але це нічого не робить. Android 4.0+.
— Azurespot

3
Якщо onBackStackChanged () не замінює, переконайтеся, що ваша діяльність реалізує інтерфейс FragmentManager.OnBackStackChangedListener.
— CBA110,

41

Зрозумів. просто перевизначте onOptionsItemSelected в хостинговій діяльності та спливаюче backstack, наприклад

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home: {
            FragmentManager fm = getSupportFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStack();
                return true;
            }
            break;
        }
    }
    return super.onOptionsItemSelected(item);
}

Телефонуйте getActionBar().setDisplayHomeAsUpEnabled(boolean);і getActionBar().setHomeButtonEnabled(boolean);в , onBackStackChanged()як описано у відповідь нижче.


3
вам також потрібно викликати getActivity (). getActionBar (). setDisplayHomeAsUpEnabled (false); щоб видалити кнопку вгору, як тільки ви
— висунете

Це не правильний спосіб зробити це. Він продовжує увімкнути кнопку вгору.
— Роджер Гарсон Нієто

1
Ви повинні помістити цей код всередині switchвиписки разом із справою android.R.id.home.
— Фред

18

Якщо у вас є одна з батьківських дій і ви хочете, щоб ця кнопка вгору працювала як кнопка повернення назад, ви можете використовувати такий код:

додайте це до onCreate у вашому основному класі активності

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

    });

а потім додайте onOptionsItemSelected так:

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

Як правило, я постійно цим користуюся, і здається цілком законним


1
Я спробував використати цей код саме в Activityмоєму, в надії, що він повернеться до фрагмента, з якого він починався. Кнопка "Назад" з'являється біля піктограми мого додатка, коли я переходжу до своєї Activity, але я натискаю піктограму, і нічого не відбувається (вона повинна повернутися до фрагмента). Будь-яка ідея чому? Дякую.
— Azurespot

1
@Daniel, ваш код є законним .. він працює. Ви можете просто захотіти це впорати за допомогою опції try catch просто для випадку ... ви знаєте, щоб запобігти будь-яким непередбаченим виняткам і збоям програм
— Zuko

1
@NoniA. Це повернеться лише до попереднього фрагмента (наприклад, фрагмент B -> фрагмент A), якщо ви надуваєте 1 фрагмент у новій діяльності, це не повернеться до попередньої діяльності.
— Даніель Йонкер

10

Ви можете повернутися назад за допомогою кнопки вгору, як кнопки назад;

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

8

Я знаю, що це питання давнє, але, можливо, комусь (як і мені) це також потрібно.

Якщо ваша діяльність розширює AppCompatActivity , ви можете скористатися більш простим (двохетапним) рішенням:

1 - Всякий раз, коли ви додаєте не домашній фрагмент, просто показуйте кнопку вгору, відразу після здійснення транзакції фрагмента. Подобається це:

    // ... add a fragment
    // Commit the transaction
    transaction.commit();

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - Потім при натисканні кнопки ВВЕРХ ви її приховуєте.

@Override
public boolean onSupportNavigateUp() {
    getSupportActionBar().setDisplayHomeAsUpEnabled(false);        
    return true;
}

Це воно.


7

Я використав комбінацію відповідей Роджера Гарсона Ніето та сохайлазіза . Мій додаток має єдину MainActivity і фрагменти A, B, C, які завантажуються в нього. Мій «домашній» фрагмент (A) реалізує OnBackStackChangedListener і перевіряє розмір backStack; якщо це менше одиниці, тоді вона приховує кнопку ВГОРУ. Фрагменти B і C завжди завантажують кнопку "Назад" (за моїм дизайном, B запускається з A, а C запускається з B). Сама MainActivity просто відкриває бекстейк при натисканні кнопки ВВЕРХ і має методи показати / приховати кнопку, яку називають фрагменти:

MainActivity:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        // Respond to the action bar's Up/Home button
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

public void showUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
public void hideUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); }

fragmentA (реалізує FragmentManager.OnBackStackChangedListener):

public void onCreate(Bundle savedinstanceSate) {
    // listen to backstack changes
    getActivity().getSupportFragmentManager().addOnBackStackChangedListener(this);

    // other fragment init stuff
    ...
}

public void onBackStackChanged() {
    // enable Up button only  if there are entries on the backstack
    if(getActivity().getSupportFragmentManager().getBackStackEntryCount() < 1) {
        ((MainActivity)getActivity()).hideUpButton();
    }
}

фрагментB, фрагментC:

public void onCreate(Bundle savedinstanceSate) {
    // show the UP button
    ((MainActivity)getActivity()).showUpButton();

    // other fragment init stuff
    ...
}

5

Це спрацювало для мене. Замінити onSupportNavigateUp і onBackPress, наприклад (код у Kotlin);

override fun onBackPressed() {
    val count = supportFragmentManager.backStackEntryCount
    if (count == 0) {
        super.onBackPressed()
    } else {
        supportFragmentManager.popBackStack()
    }
}

override fun onSupportNavigateUp(): Boolean {
    super.onSupportNavigateUp()
    onBackPressed()
    return true
}

Тепер у фрагменті, якщо ви відображаєте стрілку вгору

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

Натискання на нього повертає вас до попередньої активності.


5

Котлін:

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        supportFragmentManager.addOnBackStackChangedListener { setupHomeAsUp() }
        setupHomeAsUp()
    }

    private fun setupHomeAsUp() {
        val shouldShow = 0 < supportFragmentManager.backStackEntryCount
        supportActionBar?.setDisplayHomeAsUpEnabled(shouldShow)
    }

    override fun onSupportNavigateUp(): Boolean = 
        supportFragmentManager.popBackStack().run { true }

    ...
}

2

Це дуже хороше і надійне рішення: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

Хлопець створив абстрактний фрагмент, який обробляє поведінку backPress і перемикається між активними фрагментами, використовуючи шаблон стратегії.

Для когось із вас може бути невеликий недолік в абстрактному класі ...

Коротко, рішення за посиланням виглядає так:

// Abstract Fragment handling the back presses

public abstract class BackHandledFragment extends Fragment {
    protected BackHandlerInterface backHandlerInterface;
    public abstract String getTagText();
    public abstract boolean onBackPressed();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity()  instanceof BackHandlerInterface)) {
            throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
        } else {
            backHandlerInterface = (BackHandlerInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        // Mark this fragment as the selected Fragment.
        backHandlerInterface.setSelectedFragment(this);
    }

    public interface BackHandlerInterface {
        public void setSelectedFragment(BackHandledFragment backHandledFragment);
    }
}   

І використання в діяльності:

// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS 
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment

public class TheActivity extends FragmentActivity implements BackHandlerInterface {
    private BackHandledFragment selectedFragment;

    @Override
    public void onBackPressed() {
        if(selectedFragment == null || !selectedFragment.onBackPressed()) {
            // Selected fragment did not consume the back press event.
            super.onBackPressed();
        }
    }

    @Override
    public void setSelectedFragment(BackHandledFragment selectedFragment) {
        this.selectedFragment = selectedFragment;
    }
}

Хоча це посилання може відповісти на питання, краще включити сюди основні частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
— bummi

До речі: якщо ви ідентифікуєте дублікати, позначте їх як такі. Дякую.
— bummi

чи важливо встановитиSelectedFragment всередині onStart?
— В.Леонов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.