navigasi bilah tindakan dengan fragmen

88

Saya memiliki tab Actionbar / viewpager tata letak dengan tiga tab mengatakan A , B , dan C . Di tab C tab (fragmen), saya menambahkan lain misalnya fragmen fragmen D . dengan

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

Saya mengubah bilah tindakan di onResume DFragment untuk menambahkan tombol:

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

Sekarang di DFragment, ketika saya menekan tombol Back hardware (telepon), saya kembali ke tata letak Tab (ABC) asli dengan CFragment dipilih. Bagaimana saya bisa mencapai fungsi ini dengan tombol naik ke atas?

SohailAziz
sumber
Kemungkinan duplikat dari Bagaimana menerapkan onBackPressed () di Fragmen?
Code-Apprentice

Jawaban:

186

Terapkan OnBackStackChangedListenerdan tambahkan kode ini ke Aktivitas Fragmen Anda.

@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;
}
Roger Garzon Nieto
sumber
21
Tentang onSupportNavigateUp(), "Metode tidak menimpa metode dari superkelasnya".
Fred
10
Jika Anda sudah memiliki onOptionsItemSelected, Anda juga dapat memeriksa itemId android.R.id.homedaripada menambahkan onSupportNavigateUp.
domsom
1
Jika versi API> = 14, Gunakan onNavigateUp sebagai ganti onSupportNavigateUp @Override public boolean onNavigateUp () {// Metode ini dipanggil saat tombol naik ditekan. Hanya tumpukan pop-back. getFragmentManager (). popBackStack (); kembali benar; }
Tejasvi Hegde
1
Apakah seharusnya ada tanda sisipan yang ditampilkan di sebelah ikon aplikasi Anda di ActionBar? Saya tidak melihatnya ketika saya menerapkan kode ini. Saya hanya dapat mengklik ikon, tetapi tidak melakukan apa pun. Android 4.0+.
Azurespot
3
Jika onBackStackChanged () tidak menimpa, pastikan aktivitas Anda mengimplementasikan antarmuka FragmentManager.OnBackStackChangedListener.
CBA110
42

Saya mendapatkannya. cukup timpa onOptionsItemSelected dalam aktivitas hosting dan munculan backstack, mis

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

Telepon getActionBar().setDisplayHomeAsUpEnabled(boolean);dan getActionBar().setHomeButtonEnabled(boolean);masuk onBackStackChanged()seperti yang dijelaskan dalam jawaban di bawah ini.

SohailAziz
sumber
3
Anda juga harus memanggil getActivity (). getActionBar (). setDisplayHomeAsUpEnabled (false); untuk menghapus tombol atas setelah Anda memunculkan back-stack
JoP
Ini bukanlah cara yang benar untuk melakukan ini. Itu terus mengaktifkan tombol atas.
Roger Garzon Nieto
1
Anda harus meletakkan kode itu di dalam switchpernyataan dengan case android.R.id.home.
Fred
18

Jika Anda memiliki satu aktivitas orang tua dan ingin tombol atas ini berfungsi sebagai tombol kembali, Anda dapat menggunakan kode ini:

tambahkan ini ke onCreate di kelas aktivitas utama Anda

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

    });

lalu tambahkan onOptionsItemSelected seperti ini:

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

Saya biasanya menggunakan ini sepanjang waktu dan tampaknya cukup sah

Daniel Jonker
sumber
1
Saya mencoba menggunakan kode ini dengan tepat, di salah Activitysatu kode saya, dengan harapan kode itu akan kembali ke fragmen asalnya. Tombol kembali muncul di dekat ikon aplikasi saya ketika saya membuka milik saya Activity, tetapi saya mengklik ikon tersebut dan tidak ada yang terjadi (seharusnya kembali ke fragmen). Tahu kenapa? Terima kasih.
Azurespot
1
@Daniel kode Anda sah .. berfungsi. Anda mungkin ingin mengelilinginya dengan opsi coba tangkap hanya memetikan .. Anda tahu untuk mencegah pengecualian tak terduga dan aplikasi tidak bekerja
Zuko
1
@Noni. Ini hanya akan kembali ke fragmen sebelumnya (misalnya, fragmen B -> fragmen A), jika Anda memekarkan 1 fragmen di aktivitas baru, ini tidak akan kembali ke aktivitas sebelumnya.
Daniel Jonker
11

Anda dapat kembali dengan tombol atas seperti tombol kembali;

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

Saya tahu pertanyaan ini sudah tua, tetapi mungkin seseorang (seperti saya) juga membutuhkannya.

Jika Aktivitas Anda memperluas AppCompatActivity , Anda bisa menggunakan solusi yang lebih sederhana (dua langkah):

1 - Setiap kali Anda menambahkan fragmen non-home, cukup tunjukkan tombol atas, tepat setelah melakukan transaksi fragmen. Seperti ini:

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

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - Kemudian ketika tombol UP ditekan, Anda menyembunyikannya.

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

Itu dia.

martom
sumber
7

Saya menggunakan kombinasi jawaban Roger Garzon Nieto dan sohailaziz . Aplikasi saya memiliki satu MainActivity, dan fragmen A, B, C yang dimuat ke dalamnya. Fragmen "rumah" saya (A) mengimplementasikan OnBackStackChangedListener, dan memeriksa ukuran backStack; jika kurang dari satu, tombol NAIK akan disembunyikan. Fragmen B dan C selalu memuat tombol kembali (dalam desain saya, B diluncurkan dari A, dan C diluncurkan dari B). MainActivity itu sendiri hanya memunculkan backstack pada ketukan tombol UP, dan memiliki metode untuk menampilkan / menyembunyikan tombol, yang dipanggil oleh fragmen:

Aktifitas utama:

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

fragmentB, fragmentC:

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

    // other fragment init stuff
    ...
}
verboze
sumber
5

Ini berhasil untuk saya. Ganti onSupportNavigateUp dan onBackPressed, misalnya (kode di 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
}

Sekarang di fragmen, jika Anda menampilkan panah atas

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

Mengkliknya membawa Anda kembali ke aktivitas sebelumnya.

bebe
sumber
5

Kotlin:

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 }

    ...
}
fada21
sumber
2

Ini adalah solusi yang sangat bagus dan andal: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

Orang itu telah membuat fragmen abstrak yang menangani perilaku backPress dan beralih di antara fragmen aktif menggunakan pola strategi.

Bagi sebagian dari Anda mungkin ada sedikit kekurangan di kelas abstrak ...

Singkatnya, solusi dari tautan tersebut berjalan seperti ini:

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

Dan penggunaan dalam aktivitas:

// 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;
    }
}
Amio.io
sumber
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah.
bummi
BTW: jika Anda mengidentifikasi duplikat, tandai seperti itu. Terima kasih.
bummi
apakah penting untuk setSelectedFragment di dalam onStart?
VLeonovs