Impostazione del titolo ActionBar personalizzato dal frammento


90

Nel mio Main FragmentActivity, ho impostato il mio ActionBartitolo personalizzato in questo modo:

    LayoutInflater inflator = (LayoutInflater) this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflator.inflate(R.layout.custom_titlebar, null);

    TextView tv = (TextView) v.findViewById(R.id.title);
    Typeface tf = Typeface.createFromAsset(this.getAssets(),
            "fonts/capsuula.ttf");
    tv.setTypeface(tf);
    tv.setText(this.getTitle());

    actionBar.setCustomView(v);

Funziona perfettamente. Tuttavia, una volta aperto altro Fragments, voglio che il titolo cambi. Non sono sicuro di come accedere al Main Activityper farlo? In passato, ho fatto questo:

((MainFragmentActivity) getActivity()).getSupportActionBar().setTitle(
            catTitle);

Qualcuno può consigliare il metodo corretto?

XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:text=""
        android:textColor="#fff"
        android:textSize="25sp" />

</RelativeLayout>

stackoverflow.com/a/28279341/1651286 dovrebbe essere la risposta accettata a causa della sua scalabilità. poiché tutti gli altri approcci rendono il frammento legato a una particolare attività, che non è un design scalabile, e se lo stesso frammento deve essere utilizzato con più attività, anche questo è ciò che consiglia anche il framework Android.
Akhil Dad,

Risposte:


98

=== Aggiornamento 30 ottobre 2019 ===

Poiché abbiamo nuovi componenti come ViewModel e LiveData , possiamo avere un modo diverso / più semplice per aggiornare il titolo dell'attività da Fragment utilizzando ViewModel e Live Data

Attività

class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)
    if (savedInstanceState == null) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, MainFragment.newInstance())
            .commitNow()
    }
    viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
    viewModel.title.observe(this, Observer {
        supportActionBar?.title = it
    })
} }

MainFragment

class MainFragment : Fragment() {
companion object {
    fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View {
    return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    activity?.run {
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
    } ?: throw Throwable("invalid activity")
    viewModel.updateActionBarTitle("Custom Title From Fragment")
} }

E MainModelView:

class MainViewModel : ViewModel() {
private val _title = MutableLiveData<String>()
val title: LiveData<String>
get() = _title
fun updateActionBarTitle(title: String) = _title.postValue(title) }

Quindi puoi aggiornare il titolo dell'attività da Fragment usando viewModel.updateActionBarTitle("Custom Title From Fragment")

=== Aggiornamento 10 aprile 2015 ===

È necessario utilizzare listener per aggiornare il titolo della barra delle azioni

Frammento:

public class UpdateActionBarTitleFragment extends Fragment {
    private OnFragmentInteractionListener mListener;

    public UpdateActionBarTitleFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (mListener != null) {
            mListener.onFragmentInteraction("Custom Title");
        }
        return inflater.inflate(R.layout.fragment_update_action_bar_title2, container, false);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnFragmentInteractionListener {
        public void onFragmentInteraction(String title);
    }
}

E attività:

public class UpdateActionBarTitleActivity extends ActionBarActivity implements UpdateActionBarTitleFragment.OnFragmentInteractionListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_update_action_bar_title);
    }

    @Override
    public void onFragmentInteraction(String title) {
        getSupportActionBar().setTitle(title);
    }
}

Maggiori informazioni qui: https://developer.android.com/training/basics/fragments/communicating.html


1
Ha funzionato per me! Ho appena usato getActionBar (). SetTitle (title) invece nell'attività. Grazie
luckyreed76

1
Esattamente quello che stavo cercando, ha funzionato meglio per me della risposta scelta. Grazie!
dstrube

1
Questa dovrebbe essere la risposta accettata! Mostra correttamente come dovrebbe essere fatto: se un frammento vuole comunicare con la sua attività di hosting, la comunicazione dovrebbe sempre avvenire tramite un'interfaccia. Il frammento fornisce l'interfaccia e l'attività la implementa! Se più frammenti devono comunicare allo stesso modo con un'attività, scrivi un frammento astratto che fornisca l'interfaccia e poi lascia che ogni frammento erediti da questo "frammento di base".
winklerrr

3
A proposito: il metodo onAttach (Activity) utilizzato in questa risposta è obsoleto a questo punto. Controllare all'interno del onAttach(Context)metodo se l'attività host passata implementa l'interfaccia richiesta (recuperare l'attività host tramite context.getActivity()).
winklerrr

2
Dopo molti anni ho cambiato questo nella risposta accettata perché, come sappiamo, le interfacce sono il modo in cui i frammenti e le attività devono comunicare.
TheLettuceMaster

150

Quello che stai facendo è corretto. Fragmentsnon hai accesso alle ActionBarAPI, quindi devi chiamare getActivity. A meno che la tua non Fragmentsia una classe interna statica, nel qual caso dovresti creare un WeakReferenceal genitore e chiamare Activity. getActionBarda li.

Per impostare il titolo per il tuo ActionBar, mentre usi un layout personalizzato, nel tuo Fragmentdovrai chiamare getActivity().setTitle(YOUR_TITLE).

Il motivo per cui chiami setTitleè perché chiami getTitlecome titolo del tuo ActionBar. getTitlerestituisce il titolo per quello Activity.

Se non vuoi ricevere una chiamata getTitle, dovrai creare un metodo pubblico che imposti il ​​testo del tuo TextViewnel file Activityche ospita il file Fragment.

Nella tua attività :

public void setActionBarTitle(String title){
    YOUR_CUSTOM_ACTION_BAR_TITLE.setText(title);
}

Nel tuo frammento :

((MainFragmentActivity) getActivity()).setActionBarTitle(YOUR_TITLE);

Documenti:

Activity.getTitle

Activity.setTitle

Inoltre, non è necessario chiamare this.whateveril codice fornito, solo un suggerimento.


Ci provo e non riesco a farlo funzionare. Per quel che vale, ho postato il mio XMLe ho anche rimosso "questo". Nessun cambiamento ... E no, non è una staticclasse interna.
TheLettuceMaster

Aspetta, cosa non funziona? Nel tuo OP non dici niente che non funziona, dici solo di voler conoscere il metodo "corretto" per impostare il titolo in ActionBarda a Fragment. Inoltre, non stavo offrendo la rimozione this.whatevercome soluzione a nulla, era solo un suggerimento per la formattazione del codice.
adneal

Penso di aver capito con cosa hai problemi e ho modificato la mia risposta di conseguenza.
adneal

Risposta perfetta Thankx
Ammar ali

@KickingLettuce, ho lottato con questa risposta per un po 'fino a quando non l'ho fatta funzionare (è per questo che l'ho votata positivamente, così come la tua domanda): nella mia attività principale del menu_actriquadro di navigazione ( ) ho creato "mTitle" globale e fragment, prima assegno un titolo a "mTitle" ( ( (menu_act) getActivity() ).mTitle = "new_title"), e subito lo faccio ( (menu_act) getActivity() ).restoreActionBar();. Dentro "restoreActionBar ()" ho "actionBar.setTitle (mTitle);".
Jose Manuel Abarca Rodríguez

29

Gli esempi di Google tendono a usarlo all'interno dei frammenti.

private ActionBar getActionBar() {
    return ((ActionBarActivity) getActivity()).getSupportActionBar();
}

Il frammento apparterrà a una ActionBarActivity ed è qui che si trova il riferimento alla barra delle azioni. Questo è più pulito perché il frammento non ha bisogno di sapere esattamente di che attività si tratta, deve solo appartenere a un'attività che implementa ActionBarActivity. Ciò rende il frammento più flessibile e può essere aggiunto a più attività come previsto.

Ora, tutto ciò che devi fare nel frammento è.

getActionBar().setTitle("Your Title");

Funziona bene se si dispone di un frammento di base da cui ereditano i frammenti invece della normale classe di frammento.

public abstract class BaseFragment extends Fragment {
    public ActionBar getActionBar() {
        return ((ActionBarActivity) getActivity()).getSupportActionBar();
    }
}

Quindi nel tuo frammento.

public class YourFragment extends BaseFragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getActionBar().setTitle("Your Title");
    }
}

Grazie. soluzione molto bella, in questo modo puoi anche passare la visualizzazione personalizzata alla tua barra delle azioni.
Amir

Con gli aggiornamenti recenti su Android SDK, invece di ActionBarActivity, potresti voler eseguire il downcast su AppCompatActivity nel caso in cui utilizzi la libreria di compatibilità con le versioni precedenti v7 (cosa che probabilmente dovresti).
fr4gus

8

L'impostazione Activitydel titolo da un Fragmentincasina i livelli di responsabilità. Fragmentè contenuto all'interno di un Activity, quindi questo è il Activity, che dovrebbe impostare il proprio titolo in base al tipo di Fragmentper esempio.

Supponi di avere un'interfaccia:

interface TopLevelFragment
{
    String getTitle();
}

I messaggi Fragmentche possono influenzare il Activitytitolo di implementano quindi questa interfaccia. Durante l'attività di hosting scrivi:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fm = getFragmentManager();
    fm.beginTransaction().add(0, new LoginFragment(), "login").commit();
}

@Override
public void onAttachFragment(Fragment fragment)
{
    super.onAttachFragment(fragment);

    if (fragment instanceof TopLevelFragment)
        setTitle(((TopLevelFragment) fragment).getTitle());
}

In questo modo Activitysi ha sempre il controllo su quale titolo usare, anche se TopLevelFragmentsi combinano più s, il che è del tutto possibile su un tablet.


6

Non penso che la risposta accettata sia una risposta perfetta per questo. Poiché tutte le attività che utilizzano

Barra degli strumenti

sono estesi utilizzando

AppCompatActivity

, i frammenti richiamati da esso possono utilizzare il codice indicato di seguito per modificare il titolo.

((AppCompatActivity) context).getSupportActionBar().setTitle("Your Title");

5

Nel frammento che possiamo usare in questo modo, funziona bene per me.

getActivity().getActionBar().setTitle("YOUR TITLE");

Questo non funziona quando la barra degli strumenti della nostra attività ha un TextView che ha il ruolo del titolo
Simon

4

Nel caso in cui tu abbia problemi con il codice, prova a inserire getSupportActionBar().setTitle(title)all'interno onResume()del tuo frammento invece di onCreateView(...)ie

In MainActivity.java :

public void setActionBarTitle(String title) {
    getSupportActionBar().setTitle(title);
}

In frammento:

 @Override
 public void onResume(){
     super.onResume();
     ((MainActivity) getActivity()).setActionBarTitle("Your Title");
 }

Questo era il mio problema: dove stavo impostando il titolo. Tuttavia, è stato ((MainActivity) getActivity()).setTitle("title")sufficiente. A Kotlin, il mio frammento sì activity!!.title = "title.
Joe Lapp,

2

Utilizza il seguente:

getActivity().setTitle("YOUR_TITLE");

Questa risposta è per cambiare il titolo dell'attività, la domanda riguarda invece il titolo della ActionBar.
David d C e Freitas

Grazie @Anisetti! È proprio quello che ho fatto nella classe Frammento.
Francis Rodrigues

2

Ecco la mia soluzione per impostare il titolo ActionBar dai frammenti, quando si utilizza NavigationDrawer. Questa soluzione utilizza un'interfaccia in modo che i frammenti non debbano fare riferimento direttamente all'attività principale:

1) Crea un'interfaccia:

public interface ActionBarTitleSetter {
    public void setTitle(String title); 
}

2) In onAttach del frammento, eseguire il cast dell'attività sul tipo di interfaccia e chiamare il metodo SetActivityTitle:

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity);
    ((ActionBarTitleSetter) activity).setTitle(getString(R.string.title_bubbles_map)); 
}

3) Nell'attività, implementare l' interfaccia ActionBarTitleSetter :

@Override 
public void setTitle(String title) { 
    mTitle = title; 
}

Questa dovrebbe essere la risposta accettata perché tutti gli altri approcci stanno rendendo il frammento legato a un'attività particolare, che non è un design scalabile, inoltre questo è ciò che consiglia anche il framework Android
Akhil Dad

2

Miglior evento per cambio titolo onCreateOptionsMenu

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.general, container,  
    setHasOptionsMenu(true); // <-Add this line
    return view;
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // If use specific menu
    menu.clear();
    inflater.inflate(R.menu.path_list_menu, menu);
    // If use specific menu

    ((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Your Fragment");
    super.onCreateOptionsMenu(menu, inflater);
}

2

Un semplice esempio di Kotlin

Supponendo che questi gradle deps corrispondano o siano versioni successive nel tuo progetto:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Adattalo alle tue classi di frammenti:

    /**
     * A simple [Fragment] subclass.
     *
     * Updates the action bar title when onResume() is called on the fragment,
     * which is called every time you navigate to the fragment
     *
     */

    class MyFragment : Fragment() {
    private lateinit var mainActivity: MainActivity

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

       //[...]

        mainActivity = this.activity as MainActivity

       //[...]
    }

    override fun onResume() {
        super.onResume()
        mainActivity.supportActionBar?.title = "My Fragment!"
    }


    }

1

Se hai un'attività principale con molti frammenti che inserisci, di solito usando il navigationDrawer. E hai una serie di titoli per i tuoi frammenti, quando premi indietro, affinché cambino, inseriscilo nell'attività principale che contiene i frammenti

@Override
     public void onBackPressed() {

    int T=getSupportFragmentManager().getBackStackEntryCount();
    if(T==1) { finish();}

    if(T>1) {
        int tr = Integer.parseInt(getSupportFragmentManager().getBackStackEntryAt(T-2).getName());
        setTitle(navMenuTitles[tr]);  super.onBackPressed();
      }

}

Ciò presuppone che per ogni frammento gli si dia un tag, di solito da qualche parte quando si aggiungono i frammenti all'elenco di navigationDrawer, in base alla posizione premuta nell'elenco. Quindi quella posizione è ciò che acquisisco nel tag:

    fragmentManager.beginTransaction().
replace(R.id.frame_container, fragment).addToBackStack(position).commit();

Ora, navMenuTitles è qualcosa che carichi su onCreate

 // load slide menu items
        navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);

L'array xml è una risorsa stringa di tipo array su strings.xml

 <!-- Nav Drawer Menu Items -->
    <string-array name="nav_drawer_items">
        <item>Title one</item>
        <item>Title Two</item>
    </string-array>

1

Salva la tua risposta nell'oggetto String [] e impostalo su OnTabChange () in MainActivity come Belowwww

String[] object = {"Fragment1","Fragment2","Fragment3"};

public void OnTabChange(String tabId)
{
int pos =mTabHost.getCurrentTab();     //To get tab position
 actionbar.setTitle(object.get(pos));
}


//Setting in View Pager
public void onPageSelected(int arg0) {
    mTabHost.setCurrentTab(arg0);
actionbar.setTitle(object.get(pos));
}

1

Lo svantaggio del tuo approccio al casting in questo modo

((MainFragmentActivity) getActivity()).getSupportActionBar().setTitle(
        catTitle);

è che il tuo frammento non è più riutilizzabile al di fuori di MainActivityFragment. Se non prevedi di utilizzarlo al di fuori di tale attività, non ci sono problemi. Un approccio migliore sarebbe impostare condizionatamente il titolo a seconda dell'attività. Quindi all'interno del tuo frammento, scriveresti:

if (getActivity() instanceof ActionBarActivity) {
    ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Some Title");
}

1

se stai usando il modello stabile di Android Studio 1.4 fornito da Google rispetto a quello semplice, onNavigationItemSelecteddovevi scrivere il seguente codice nel metodo in cui il tuo frammento correlato chiama la condizione if.

 setTitle("YOUR FRAGMENT TITLE");

è meraviglioso se hai accesso al titolo direttamente dall'attività ... ma se il titolo è una stringa impostata dinamicamente nel frammento, deve esserci comunicazione tra il frammento e l'attività
io_

1

Sto ottenendo una soluzione molto semplice per impostare il titolo ActionBar in un frammento o in qualsiasi attività senza alcun mal di testa.

Basta modificare l'xml dove è definita la barra degli strumenti come di seguito:

<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimaryDark"
            app:popupTheme="@style/AppTheme.PopupOverlay" >

            <TextView
                style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
                android:id="@+id/toolbar_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/app_name"
                />
            </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout> 

1) Se vuoi impostare la barra delle azioni in un frammento, allora:

Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);

Per utilizzarlo da qualsiasi luogo, è possibile definire un metodo nell'attività

public void setActionBarTitle(String title) {
        toolbarTitle.setText(title);
    }

Per chiamare questo metodo in attività, chiamalo semplicemente.

setActionBarTitle("Your Title")

Per chiamare questo metodo dal frammento dell'attività, chiamalo semplicemente.

((MyActivity)getActivity()).setActionBarTitle("Your Title");

Eccellente! L'utilizzo di toolbar_title sovrascrive il titolo del frammento se si utilizzano i componenti di navigazione Android.
Paixols

0

Solo per aggiungere alla risposta selezionata, potresti anche voler aggiungere un secondo metodo alla tua attività principale. Quindi finiresti con i seguenti metodi nella tua attività principale:

public void setActionBarTitle(String title) {
    getSupportActionBar().setTitle(title);
}

public void setActionBarTitle(int resourceId) {
    setActionBarTitle(getResources().getString(resourceId);
}

Ciò ti consentirà di impostare il titolo sia da una variabile String che da un ID risorsa come R.id.this_is_a_stringdal tuo file strings.xml. Funzionerà anche un po 'più come getSupportActionBar().setTitle()funziona poiché ti consente di passare un ID risorsa.


0

Ci sono molti modi come descritto sopra. Puoi anche farlo onNavigationDrawerSelected()nel tuo fileDrawerActivity

public void setTitle(final String title){
    ((TextView)findViewById(R.id.toolbar_title)).setText(title);
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    fragment = null;
    String title = null;
    switch(position){

    case 0:
        fragment = new HomeFragment();
        title = "Home";
        break;
    case 1:
        fragment = new ProfileFragment();
        title = ("Find Work");
        break;
    ...
    }
    if (fragment != null){

        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager
        .beginTransaction()
        .replace(R.id.container,
                fragment).commit();

        //The key is this line
        if (title != null && findViewById(R.id.toolbar_title)!= null ) setTitle(title);
    }
}

0

Almeno per me, c'era una risposta facile (dopo molte ricerche in giro) alla modifica del titolo di una scheda in fase di esecuzione:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos) .setText ("Il mio nuovo testo");


0

Se stai usando ViewPager(come la mia custodia) puoi usare:

getSupportActionBar().setTitle(YOURE_TAB_BAR.getTabAt(position).getText());

nel onPageSelectedmetodo del tuoVIEW_PAGER.addOnPageChangeListener


0

Nella tua MainActivity, sotto onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

E nella tua attività di frammento sotto onResume:

getActivity().setTitle(R.string.app_name_science);

Opzionale: - se mostrano un avviso di riferimento nullo

Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);


Objects.requireNonNull(getActivity()).setTitle(R.string.app_name_science);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.