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


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.