Définition du titre ActionBar personnalisé à partir d'un fragment

90

Dans ma main FragmentActivity, je configure mon ActionBartitre personnalisé comme ceci:

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

Cela fonctionne parfaitement. Cependant, une fois que j'en ouvre un autre Fragments, je veux que le titre change. Je ne sais pas comment accéder au Main Activitypour faire cela? Dans le passé, j'ai fait ceci:

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

Quelqu'un peut-il vous conseiller sur la bonne méthode?

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>
TheLettuceMaster
la source
stackoverflow.com/a/28279341/1651286 devrait être la réponse acceptée en raison de son évolutivité. parce que toutes les autres approches rendent le fragment lié à une activité particulière, qui n'est pas une conception évolutive, que se passe-t-il si le même fragment doit être utilisé avec plusieurs activités, c'est également ce que le framework Android recommande également.
Akhil Dad
Regardez ce lien stackoverflow.com/a/46705242/1770868
Ahmad Aghazadeh

Réponses:

98

=== Mise à jour du 30 octobre 2019 ===

Puisque nous avons de nouveaux composants tels que ViewModel et LiveData , nous pouvons avoir un moyen différent / plus simple de mettre à jour le titre de l'activité à partir de Fragment en utilisant ViewModel et Live Data

Activité

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

Et MainModelView:

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

Et puis vous pouvez mettre à jour le titre de l'activité à partir de Fragment en utilisant viewModel.updateActionBarTitle("Custom Title From Fragment")

=== Mise à jour du 10 avril 2015 ===

Vous devez utiliser l'écouteur pour mettre à jour le titre de votre barre d'action

Fragment:

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

Et activité:

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

En savoir plus ici: https://developer.android.com/training/basics/fragments/communicating.html

Frank Nguyen
la source
1
Cela a fonctionné pour moi! Je viens d'utiliser getActionBar (). SetTitle (title) à la place dans l'activité. Merci
luckyreed76
1
Exactement ce que je cherchais - fonctionnait mieux pour moi que la réponse choisie. Merci!
dstrube
1
Cela devrait être la réponse acceptée! Il montre correctement comment cela doit être fait: si un fragment veut communiquer avec son activité d'hébergement, la communication doit toujours se faire via une interface. Le fragment fournit l'interface et l'activité l'implémente! Si plusieurs fragments doivent communiquer de la même manière avec une activité, écrivez un fragment abstrait qui fournit l'interface et laissez ensuite chaque fragment hériter de ce "fragment de base".
winklerrr
3
À propos: la méthode onAttach (Activity) utilisée dans cette réponse est obsolète pour le moment. Vérifiez à l'intérieur de la onAttach(Context)méthode si l'activité d'hôte passée implémente l'interface requise (récupérez l'activité de l'hôte via context.getActivity()).
winklerrr
2
Après de nombreuses années, j'ai changé cela pour devenir la réponse acceptée car, comme nous le savons, les interfaces sont le moyen par lequel les fragments et les activités doivent communiquer.
TheLettuceMaster
150

Ce que vous faites est correct. Fragmentsn'ont pas accès aux ActionBarAPI, vous devez donc appeler getActivity. Sauf si vous Fragmentêtes une classe interne statique, auquel cas vous devez créer un WeakReferencepour le parent et appeler Activity. getActionBarDe là.

Pour définir le titre de votre ActionBar, tout en utilisant une mise en page personnalisée, dans votre, Fragmentvous devrez appeler getActivity().setTitle(YOUR_TITLE).

La raison pour laquelle vous appelez setTitleest que vous appelez getTitlecomme titre de votre ActionBar. getTitlerenvoie le titre pour cela Activity.

Si vous ne souhaitez pas recevoir d'appel getTitle, vous devrez créer une méthode publique qui définit le texte de votre TextViewdans le Activityqui héberge le Fragment.

Dans votre activité :

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

Dans votre fragment :

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

Documents:

Activity.getTitle

Activity.setTitle

De plus, vous n'avez pas besoin d'appeler this.whateverle code que vous avez fourni, juste un conseil.

adné
la source
J'essaye et je ne peux pas le faire fonctionner. Pour ce que ça vaut, j'ai posté mon XMLet également supprimé "ceci". Aucun changement ... Et non, ce n'est pas une staticclasse interne.
TheLettuceMaster
Attendez, qu'est-ce qui ne fonctionne pas? Dans votre OP, vous ne mentionnez rien qui ne fonctionne pas , vous mentionnez seulement vouloir connaître la méthode "appropriée" pour définir le titre dans le ActionBarfrom a Fragment. De plus, je n'offrais pas la suppression this.whatevercomme solution à quoi que ce soit, ce n'était qu'un conseil de formatage de code.
adneal
Je pense comprendre ce que vous rencontrez et j'ai modifié ma réponse en conséquence.
adneal
Thankx perfect answer
Ammar ali
@KickingLettuce, j'ai du mal avec cette réponse pendant un certain temps jusqu'à ce que je la fasse fonctionner (c'est pourquoi je l'ai votée, ainsi que votre question): dans mon activité principale du tiroir de navigation ( menu_act) j'ai créé "mTitle" global, et, dans un fragment, j'attribue d'abord un titre à "mTitle" ( ( (menu_act) getActivity() ).mTitle = "new_title"), et je le fais immédiatement ( (menu_act) getActivity() ).restoreActionBar();. Dans "restoreActionBar ()", j'ai "actionBar.setTitle (mTitle);".
Jose Manuel Abarca Rodríguez
29

Les exemples Google ont tendance à l'utiliser dans les fragments.

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

Le fragment appartiendra à une ActionBarActivity et c'est là que se trouve la référence à la barre d'actions. C'est plus propre car le fragment n'a pas besoin de savoir exactement de quelle activité il s'agit, il doit seulement appartenir à une activité qui implémente ActionBarActivity. Cela rend le fragment plus flexible et peut être ajouté à plusieurs activités comme prévu.

Maintenant, tout ce que vous avez à faire dans le fragment est.

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

Cela fonctionne bien si vous avez un fragment de base dont vos fragments héritent au lieu de la classe de fragment normale.

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

Puis dans votre fragment.

public class YourFragment extends BaseFragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getActionBar().setTitle("Your Title");
    }
}
Kalel Wade
la source
Merci. très belle solution, de cette façon vous pouvez également passer une vue personnalisée à votre barre d'action.
Amir
Avec les mises à jour récentes du SDK Android, au lieu d'ActionBarActivity, vous souhaiterez peut-être passer à AppCompatActivity au cas où vous utilisez la bibliothèque de compatibilité descendante v7 (ce que vous devriez probablement).
fr4gus
8

Le réglage Activitydu titre à partir d'un Fragmentgâchis les niveaux de responsabilité. Fragmentest contenu dans un Activity, donc c'est le Activity, qui devrait définir son propre titre en fonction du type de Fragmentpar exemple.

Supposons que vous ayez une interface:

interface TopLevelFragment
{
    String getTitle();
}

Les Fragments qui peuvent influencer le Activitytitre du s implémentent alors cette interface. Pendant l'activité d'hébergement, vous écrivez:

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

De cette manière, Activityon contrôle toujours le titre à utiliser, même si plusieurs TopLevelFragments sont combinés, ce qui est tout à fait possible sur une tablette.

Aleks N.
la source
6

Je ne pense pas que la réponse acceptée soit une réponse parfaite. Depuis toutes les activités qui utilisent

Barre d'outils

sont étendus en utilisant

AppCompatActivity

, les fragments appelés à partir de celui-ci peuvent utiliser le code mentionné ci-dessous pour changer le titre.

((AppCompatActivity) context).getSupportActionBar().setTitle("Your Title");
Manoj Perumarath
la source
5

Dans le Fragment, nous pouvons utiliser comme ça, ça marche bien pour moi.

getActivity().getActionBar().setTitle("YOUR TITLE");
NagarjunaReddy
la source
Cela ne fonctionne pas lorsque la barre d'outils de notre activité a un TextView qui a le rôle du titre
Simon
4

Juste au cas où vous rencontriez des problèmes avec le code, essayez de mettre à l' getSupportActionBar().setTitle(title)intérieur onResume()de votre fragment au lieu de onCreateView(...)ie

Dans MainActivity.java :

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

En fragment:

 @Override
 public void onResume(){
     super.onResume();
     ((MainActivity) getActivity()).setActionBarTitle("Your Title");
 }
realpac
la source
C'était mon problème - je définissais le titre. Cependant, ((MainActivity) getActivity()).setTitle("title")suffisait. À Kotlin, mon fragment le fait activity!!.title = "title.
Joe Lapp
2

Utilisez le suivant:

getActivity().setTitle("YOUR_TITLE");
Anisetti Nagendra
la source
Cette réponse consiste à changer le titre de l'activité, la question concerne plutôt le titre de l'ActionBar.
David d C e Freitas
Merci @Anisetti! C'est exactement ce que j'ai fait en classe Fragment.
Francis Rodrigues
2

Voici ma solution pour définir le titre ActionBar à partir de fragments, lors de l'utilisation de NavigationDrawer. Cette solution utilise une interface afin que les fragments n'aient pas besoin de référencer directement l'activité parente:

1) Créez une interface:

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

2) Dans le onAttach du fragment, transtypez l'activité en type Interface et appelez la méthode SetActivityTitle:

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

3) Dans l'activité, implémentez l' interface ActionBarTitleSetter :

@Override 
public void setTitle(String title) { 
    mTitle = title; 
}
Assaf S.
la source
Cela devrait être la réponse acceptée, car toutes les autres approches créent un fragment lié à une activité particulière, ce qui n'est pas une conception évolutive, c'est également ce que le cadre Android recommande également
Akhil Dad
2

Meilleur événement pour changer de titre 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);
}
Ahmad Aghazadeh
la source
2

Un exemple simple de Kotlin

En supposant que ces niveaux correspondent ou sont une version supérieure de votre projet:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Adaptez ceci à vos classes de fragments:

    /**
     * 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!"
    }


    }
lasec0203
la source
1

Si vous avez une activité principale avec de nombreux fragments que vous mettez, généralement en utilisant le navigateurDrawer. Et vous avez une panoplie de titres pour vos fragments, lorsque vous appuyez en arrière, pour qu'ils changent, mettez cela dans l'activité principale qui contient les fragments

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

}

Cela suppose que pour chaque fragment, vous lui attribuez une balise, généralement quelque part lorsque vous ajoutez les fragments à la liste de navigationDrawer, en fonction de la position appuyée sur la liste. Donc, cette position est ce que je capture sur l'étiquette:

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

Maintenant, le navMenuTitles est quelque chose que vous chargez sur le onCreate

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

Le tableau xml est une ressource de chaîne de type tableau sur strings.xml

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

Enregistrez votre réponse dans l'objet String [] et définissez-le OnTabChange () dans MainActivity comme ci-dessouswww

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));
}
Narendra Kumar
la source
1

L'inconvénient de votre approche du casting comme ça

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

est que votre fragment n'est plus réutilisable en dehors de MainActivityFragment. Si vous ne prévoyez pas de l'utiliser en dehors de cette activité, il n'y a pas de problème. Une meilleure approche serait de définir conditionnellement le titre en fonction de l'activité. Donc, à l'intérieur de votre fragment, vous écririez:

if (getActivity() instanceof ActionBarActivity) {
    ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Some Title");
}
Mieczysław Daniel Dyba
la source
1

si vous utilisez le modèle stable android studio 1.4 fourni par google, vous deviez écrire le code suivant dans la onNavigationItemSelectedméthode dans laquelle votre fragment associé appelle la condition if.

 setTitle("YOUR FRAGMENT TITLE");
Manan Patel
la source
c'est merveilleux si vous avez accès au titre directement à partir de l'activité ... mais si le titre est une chaîne définie de manière dynamique dans le fragment, il doit y avoir une communication entre le fragment et l'activité
me_
1

J'obtiens une solution très simple pour définir le titre ActionBar dans un fragment ou une activité sans aucun mal de tête.

Modifiez simplement le xml où est définie la barre d'outils comme ci-dessous:

<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) Si vous souhaitez définir la barre d'actions dans un fragment, alors:

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

Pour l'utiliser de n'importe où, vous pouvez définir une méthode dans l'activité

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

Pour appeler cette méthode en activité, appelez-la simplement.

setActionBarTitle("Your Title")

Pour appeler cette méthode à partir d'un fragment de l'activité, appelez-la simplement.

((MyActivity)getActivity()).setActionBarTitle("Your Title");
JoboFive
la source
Excellent! L'utilisation de toolbar_title remplace le titre du fragment si vous utilisez des composants de navigation Android.
Paixols
0

Juste pour ajouter à la réponse sélectionnée, vous pouvez également ajouter une deuxième méthode à votre activité principale. Vous vous retrouveriez donc avec les méthodes suivantes dans votre activité principale:

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

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

Cela vous permettra de définir le titre à la fois à partir d'une variable String et d'un ID de ressource tel que R.id.this_is_a_stringvotre fichier strings.xml. Cela fonctionnera également un peu plus comme cela getSupportActionBar().setTitle()fonctionne car cela vous permet de transmettre un ID de ressource.

CodyEngel
la source
0

Il existe de nombreuses façons, comme indiqué ci-dessus. Vous pouvez également le faire onNavigationDrawerSelected()dans votreDrawerActivity

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);
    }
}
tromperie
la source
0

Au moins pour moi, il y avait une réponse facile (après beaucoup de recherches) pour changer le titre d'un onglet au moment de l'exécution:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos) .setText ("Mon nouveau texte");

marque
la source
0

Si vous utilisez ViewPager(comme mon cas), vous pouvez utiliser:

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

dans la onPageSelectedméthode de votreVIEW_PAGER.addOnPageChangeListener

Reza
la source
0

Dans votre MainActivity, sous onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Et dans votre activité de fragment sous onResume:

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

Facultatif: - s'ils affichent un avertissement de référence nulle

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


Objects.requireNonNull(getActivity()).setTitle(R.string.app_name_science);
Amit Singh
la source