web-dev-qa-db-fra.com

Comment définir le titre dans la barre d'application avec le composant Architecture de navigation

J'essayais le composant d'architecture de navigation et j'ai maintenant des difficultés à définir le titre. Comment définir le titre par programme et comment cela fonctionne-t-il?

Pour effacer ma question, prenons un exemple, où, j'ai installé une application simple avec MainActivity hébergeant le contrôleur hôte de navigation, le MainFragment a un bouton et en cliquant sur le bouton il va à DetailFragment.

Le même code d'une autre question de plusieurs barres d'application sur le débordement de pile.

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Setting up a back button
        NavController navController = Navigation.findNavController(this, R.id.nav_Host);
        NavigationUI.setupActionBarWithNavController(this, navController);
    }

    @Override
    public boolean onSupportNavigateUp() {
        return Navigation.findNavController(this, R.id.nav_Host).navigateUp();
    }
}

MainFragment

public class MainFragment extends Fragment {

    public MainFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Button buttonOne = view.findViewById(R.id.button_one);
        buttonOne.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.detailFragment));
    }

}

DetailFragment

public class DetailFragment extends Fragment {

    public DetailFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_detail, container, false);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:animateLayoutChanges="true"
    tools:context=".MainActivity">

    <com.google.Android.material.appbar.AppBarLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:animateLayoutChanges="true"
        Android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            Android:id="@+id/toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="?attr/actionBarSize"
            Android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.Android.material.appbar.AppBarLayout>

    <fragment
        Android:id="@+id/nav_Host"
        Android:name="androidx.navigation.fragment.NavHostFragment"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="top"
        Android:layout_marginTop="?android:attr/actionBarSize"
        app:defaultNavHost="true"
        app:layout_anchor="@id/bottom_appbar"
        app:layout_anchorGravity="top"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:navGraph="@navigation/mobile_navigation" />

    <com.google.Android.material.bottomappbar.BottomAppBar
        Android:id="@+id/bottom_appbar"
        Android:layout_width="match_parent"
        Android:layout_height="?android:attr/actionBarSize"
        Android:layout_gravity="bottom" />

    <com.google.Android.material.floatingactionbutton.FloatingActionButton
        Android:id="@+id/fab"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        app:layout_anchor="@id/bottom_appbar" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

navigation.xml

<navigation xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/mobile_navigation"
    app:startDestination="@id/mainFragment">
    <fragment
        Android:id="@+id/mainFragment"
        Android:name="com.example.MainFragment"
        Android:label="fragment_main"
        tools:layout="@layout/fragment_main" >
        <action
            Android:id="@+id/toAccountFragment"
            app:destination="@id/detailFragment" />
    </fragment>
    <fragment
        Android:id="@+id/detailFragment"
        Android:name="com.example.DetailFragment"
        Android:label="fragment_account"
        tools:layout="@layout/fragment_detail" />
</navigation>

Ainsi, lorsque je démarre mon application, le titre est "MainActivity" . Comme d'habitude, il montre le MainFragment qui contient le bouton pour aller à DetailFragment. Dans le DialogFragment j'ai défini le titre comme:

getActivity().getSupportActionBar().setTitle("Detail");

Premier problème: Donc, en cliquant sur le bouton sur le MainFragment pour aller à DetailFragment, il y va et le titre change détailler". Mais en cliquant sur le bouton de retour, le titre devient "fragment_main" . J'ai donc ajouté cette ligne de code à MainFragment:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // ...

    //Showing the title 
    Navigation.findNavController(view)
      .getCurrentDestination().setLabel("Hello");
}

Maintenant, tout en revenant de DetailFragment à MainFragment, le titre devient "Bonjour". Mais voici le deuxième problème , lorsque je ferme l'application et que je recommence, le titre revient à "MainActivity" bien qu'il devrait afficher "Bonjour" à la place, tu sais?

Ok, puis ajouter setTitle("Hello") dans MainFrgment ne fonctionne pas trop. Par exemple, l'activité démarre et le titre est "Bonjour", allez dans DetailsFragment et appuyez à nouveau sur le bouton Retour, le titre revient à "fragment_main".

La seule solution est d'avoir à la fois setTitle("Hello") et Navigation.findNavController(view).getCurrentDestination().setLabel("Hello") dans MainFragment.

Alors, quelle est la bonne façon d'afficher le titre des fragments à l'aide du composant de navigation?

19
Rajarshi

C'est en fait à cause de:

Android:label="fragment_main"

Que vous avez défini dans le xml.

Alors, quelle est la bonne façon d'afficher le titre pour Fragments en utilisant le composant de navigation?

setTitle() fonctionne à ce stade. Mais, comme vous définissez le libellé pour ces Fragment, il peut afficher à nouveau le libellé lors de la recréation du Activity. La solution supprimera probablement Android:label Et fera ensuite vos choses avec du code:

getActivity().getSupportActionBar().setTitle("yourtitle");

Ou:

((AppCompatActivity) getActivity()).getSupportActionBar().setSubtitle();

Dans onCreateView().


Solution de contournement trouvée:

interface TempToolbarTitleListener {
    fun updateTitle(title: String)
}

class MainActivity : AppCompatActivity(), TempToolbarTitleListener {

    ...

    override fun updateTitle(title: String) {
        binding.toolbar.title = title
    }
}

Ensuite:

(activity as TempToolbarTitleListener).updateTitle("custom title")

Vérifiez également ceci: titre Dynamic ActionBar d'un fragment utilisant la navigation AndroidX

2
ʍѳђઽ૯ท

L'API peut avoir changé depuis que la question a été posée, mais vous pouvez maintenant indiquer une référence à une chaîne dans les ressources de votre application dans l'étiquette du graphique de navigation.

enter image description here

C'est très utile si vous voulez un titre statique pour vos fragments.

1
malrok44

Vous pouvez utiliser ce code dans votre fragment si vous ne spécifiez pas votre barre d'application (barre d'application par défaut)

(activity as MainActivity).supportActionBar?.title = "Your Custom Title"

N'oubliez pas de supprimer le Android:label attribut dans votre graphique de navigation

Code heureux ^ - ^

1
Alif Al-Gibran

Je suggère d'inclure AppBar dans chaque écran. Pour éviter les doublons de code, créez un assistant, qui construit AppBar, en prenant le titre comme paramètre. Appelez ensuite l'assistant dans chaque classe d'écran.

1
polina-c

Une autre approche pourrait être la suivante:

fun Fragment.setToolbarTitle(title: String) {
    (activity as NavigationDrawerActivity).supportActionBar?.title = title
}
0
drindt

Vous pouvez utiliser le fichier xml du graphique de navigation et définir le libellé du fragment sur un argument. Ensuite, dans votre fragment parent, vous pouvez passer un argument à l'aide de SafeArgs et fournir une valeur par défaut pour éviter que le titre soit nul ou vide.

<!--set the fragment's title to characters name passed as an argument-->
<fragment
    Android:id="@+id/characterDetailFragment2"
    Android:name="ui.character.CharacterDetailFragment"
    Android:label="{character_name}"
    tools:layout="@layout/fragment_character_detail">
    <argument
        Android:name="character_name"
        Android:defaultValue="Name"
        app:argType="string" />
</fragment>
0
Alex Shevchyshen