getSupportActionBar dari dalam Fragment ActionBarCompat

102

Saya memulai proyek baru yang menggunakan perpustakaan dukungan AppCompat/ActionBarCompatdalam v7. Saya mencoba mencari cara untuk menggunakan getSupportActionBardari dalam sebuah fragmen. Aktivitas saya yang menghosting fragmen meluas ActionBarActivity, tetapi saya tidak melihat kelas dukungan serupa untuk Fragmen.

Dari dalam fragmen saya

    public class CrimeFragment extends Fragment {
          //...

          getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment

          //...
    }

Halaman google untuk menggunakannya ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) mengatakan seharusnya tidak ada perubahan untuk v4fragmen. Apakah saya perlu mentransmisikan semua getActivity()panggilan saya ke ActionBarActivity? Sepertinya desainnya jelek.

Paul
sumber

Jawaban:

287

Setelah Fragment.onActivityCreated (...) Anda akan memiliki aktivitas valid yang dapat diakses melalui getActivity ().

Anda harus mentransmisikannya ke ActionBarActivity kemudian melakukan panggilan ke getSupportActionBar ().

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

Anda memang membutuhkan pemerannya. Ini bukan desain yang buruk, ini kompatibilitas ke belakang.

Pierre-Antoine LaFayette
sumber
3
Terima kasih. Saya berharap ini bukan jawabannya. Saya berharap mungkin getActionBar () akan mengembalikan ActionBar v7 yang akan saya gunakan jika saya memerlukan fungsionalitas tambahan. Sekarang Fragmen saya harus mengetahui jenis Aktivitas apa yang menghostingnya.
Paul
Tidak, tidak karena getActionBar () adalah API Aktivitas yang tidak ada di versi lama SDK (pre-honeycomb). Inilah mengapa kita membutuhkan kelas dukungan yang mencerminkan fungsionalitas dari kelas dan API yang baru dan ditingkatkan di SDK yang lebih baru.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette Mengapa ini harus dilakukan di onAttach ()? Bukankah lebih baik di onActivityCreated ()?
IgorGanapolsky
Ya, karena panggilan pertama ke getSupportActionBar () akan menginisialisasi ActionBar dengan mencari tampilan dalam aktivitas, mungkin lebih baik panggilan ini dilakukan di onActivityCreated (). Saya lebih hanya mencoba menunjukkan bahwa Anda harus menunggu sampai fragmen memiliki aktivitas. Saya akan memperbarui jawabannya.
Pierre-Antoine LaFayette
2
Gunakan AppCompatActivity sebagai ganti ActionBarActivity
Aparajita Sinha
37

Meskipun pertanyaan ini sudah memiliki jawaban yang diterima, saya harus menunjukkan bahwa itu tidak sepenuhnya benar: menelepon getSupportActionBar()dari Fragment.onAttach()akan menyebabkan a NullPointerExceptionsaat aktivitas diputar.

Jawaban singkat:

Gunakan ((ActionBarActivity)getActivity()).getSupportActionBar()dalam onActivityCreated()(atau titik mana pun setelah itu dalam siklus hidupnya), bukan onAttach().

Jawaban panjang:

Alasannya adalah jika an ActionBarActivitydibuat ulang setelah rotasi, itu akan memulihkan semua Fragmen sebelum benar-benar membuat ActionBarobjek.

Kode sumber ActionBarActivitydi support-v7perpustakaan:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()membuat mImplobjek tergantung pada versi Android.
  • super.onCreate()is FragmentActivity.onCreate(), yang memulihkan fragmen sebelumnya setelah rotasi ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)adalah ActionBarActivityDelegate.onCreate(), yang membaca mHasActionBarvariabel dari gaya jendela.
  • Sebelumnya mHasActionBarbenar, getSupportActionBar()akan selalu kembali null.

Sumber untuk ActionBarActivityDelegate.getSupportActionBar():

final ActionBar getSupportActionBar() {
    // The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
    // could change after onCreate
    if (mHasActionBar || mOverlayActionBar) {
        if (mActionBar == null) {
            ... creates the action bar ...
        }
    } else {
        // If we're not set to have a Action Bar, null it just in case it's been set
        mActionBar = null;
    }
    return mActionBar;
}
matiash
sumber
2
ActionBarActivitysudah ditinggalkan. Gunakan AppCompatActivitysebagai gantinya
Saman Sattari
29

Jika seseorang menggunakan com.android.support:appcompat-v7: dan AppCompatActivity sebagai aktivitas, ini akan berfungsi

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Amir
sumber
5

di fragment.xmlTambahkan ToolbarTag dari pustaka dukungan

 <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Sekarang bagaimana kita bisa mengontrolnya dari MyFragmentkelas? Ayo lihat

onCreateViewfungsi di dalam tambahkan yang berikut ini

mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);

//add this line if you want to provide Up Navigation but don't forget to to 
//identify parent activity in manifest file
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);

dan jika Anda ingin menambahkan itemske toolbar di dalam MyFragment Anda musttambahkan baris ini di dalam onCreateViewfungsi

        setHasOptionsMenu(true);

baris ini penting, jika Anda lupa, android tidak akan mengisi Item menu Anda.

asumsikan kami mengidentifikasi mereka di menu/fragment_menu.xml

setelah itu ganti fungsi berikut

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.action_1:
            // do stuff
            return true;

        case R.id.action_2:
            // do more stuff
            return true;
    }

    return false;
}

semoga ini membantu

Basheer AL-MOMANI
sumber
5

Sebagai jawaban terbaru untuk jawaban Pierre-Antoine LaFayette

ActionBarActivity sudah tidak digunakan lagi; gunakan AppCompatActivitysebagai gantinya

((AppCompatActivity)getActivity()).getSupportActionBar();
Dasser Basyouni
sumber
3

Bagi mereka yang menggunakan kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
GzDevs
sumber