Configuración del título de la barra de acciones personalizada a partir del fragmento

90

En mi Main FragmentActivity, configuro mi ActionBartítulo personalizado así:

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

Esto funciona perfecto. Sin embargo, una vez que abro otro Fragments, quiero que cambie el título. ¿No estoy seguro de cómo acceder a Main Activitypara hacer esto? En el pasado, hice esto:

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

¿Alguien puede asesorar sobre el método adecuado?

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
fuente
stackoverflow.com/a/28279341/1651286 debería ser la respuesta aceptada debido a su escalabilidad. Debido a que todos los demás enfoques hacen que el fragmento esté vinculado a una actividad particular, que no es un diseño escalable, ¿qué pasa si el mismo fragmento tiene que usarse con múltiples actividades? También esto es lo que también recomienda el marco de Android.
Akhil Dad
Mira este enlace stackoverflow.com/a/46705242/1770868
Ahmad Aghazadeh

Respuestas:

98

=== Actualización 30 de octubre de 2019 ===

Dado que tenemos nuevos componentes como ViewModel y LiveData , podemos tener una forma diferente / más fácil de actualizar el título de la actividad desde Fragment utilizando ViewModel y Live Data

Actividad

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

Y MainModelView:

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

Y luego puede actualizar el título de la actividad desde Fragmento usando viewModel.updateActionBarTitle("Custom Title From Fragment")

=== Actualización 10 de abril de 2015 ===

Debes usar el oyente para actualizar el título de tu barra de acciones.

Fragmento:

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

Y actividad:

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

Lea más aquí: https://developer.android.com/training/basics/fragments/communicating.html

Frank Nguyen
fuente
1
¡Funcionó para mí! Solo usé getActionBar (). SetTitle (title) en su lugar en la actividad. Gracias
luckyreed76
1
Exactamente lo que estaba buscando funcionó mejor para mí que la respuesta elegida. ¡Gracias!
dstrube
1
¡Esta debería ser la respuesta aceptada! Muestra correctamente cómo se debe hacer: si un fragmento quiere comunicarse con su actividad de alojamiento, la comunicación siempre debe ocurrir a través de una interfaz. ¡El fragmento proporciona la interfaz y la actividad la implementa! Si varios fragmentos tienen que comunicarse de la misma manera con una actividad, escriba un fragmento abstracto que proporcione la interfaz y luego deje que cada fragmento herede de este "fragmento base".
winklerrr
3
Por cierto: el método onAttach (Activity) utilizado en esta respuesta está obsoleto en este momento. Verifique dentro del onAttach(Context)método si la actividad del host pasada implementa la interfaz requerida (recupere la actividad del host mediante context.getActivity()).
winklerrr
2
Después de muchos años cambié esto a la respuesta aceptada porque, como sabemos, las interfaces son la forma en que los fragmentos y las actividades necesitan comunicarse.
TheLettuceMaster
150

Lo que estás haciendo es correcto. Fragmentsno tiene acceso a las ActionBarAPI, por lo que debe llamar getActivity. A menos que Fragmentsea ​​una clase interna estática, en cuyo caso debe crear un WeakReferenceal padre y llamar a Activity. getActionBardesde allí.

Para establecer el título de su ActionBar, mientras usa un diseño personalizado, en su Fragmentdeberá llamar getActivity().setTitle(YOUR_TITLE).

La razón por la que llama setTitlees porque está llamando getTitlecomo el título de su ActionBar. getTitledevuelve el título para eso Activity.

Si no desea recibir una llamada getTitle, deberá crear un método público que establezca el texto de su TextViewen el Activityque aloja el Fragment.

En tu actividad :

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

En tu Fragmento :

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

Documentos:

Activity.getTitle

Activity.setTitle

Además, no es necesario que ingrese this.whateverel código que proporcionó, solo un consejo.

adneal
fuente
Lo intento y no puedo hacer que funcione. Por lo que vale, publiqué mi XMLy también eliminé "esto". Sin cambios ... Y no, no es una staticclase interna.
TheLettuceMaster
Espera, ¿qué no funciona? En tu OP no mencionas nada que no funcione, solo mencionas querer saber el método "adecuado" para establecer el título en el ActionBarfrom a Fragment. Además, no estaba ofreciendo la eliminación this.whatevercomo una solución a nada, eso era solo una sugerencia de formato de código.
adneal
Creo que entiendo con qué tienes problemas y edité mi respuesta en consecuencia.
adneal
Thankx perfect answer
Ammar ali
@KickingLettuce, lucho con esta respuesta por un tiempo hasta que la hice funcionar (es por eso que la voté a favor, así como tu pregunta): en mi actividad principal del cajón de navegación ( menu_act) hice global "mTitle", y, en un fragmento, primero le asigno un título a "mTitle" ( ( (menu_act) getActivity() ).mTitle = "new_title"), e inmediatamente lo hago ( (menu_act) getActivity() ).restoreActionBar();. Dentro de "restoreActionBar ()" tengo "actionBar.setTitle (mTitle);".
Jose Manuel Abarca Rodríguez
29

Los ejemplos de Google tienden a usar esto dentro de los fragmentos.

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

El fragmento pertenecerá a una ActionBarActivity y ahí es donde está la referencia a la barra de acciones. Esto es más limpio porque el fragmento no necesita saber exactamente qué actividad es, solo necesita pertenecer a una actividad que implemente ActionBarActivity. Esto hace que el fragmento sea más flexible y se puede agregar a múltiples actividades como deben.

Ahora, todo lo que necesita hacer en el fragmento es.

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

Esto funciona bien si tiene un fragmento base del que heredan sus fragmentos en lugar de la clase de fragmento normal.

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

Luego en tu fragmento.

public class YourFragment extends BaseFragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getActionBar().setTitle("Your Title");
    }
}
Kalel Wade
fuente
Gracias. muy buena solución, de esta manera también puede pasar una vista personalizada a su barra de acciones.
Amir
Con las actualizaciones recientes en Android SDK, en lugar de ActionBarActivity, es posible que desee rebajar a AppCompatActivity en caso de que esté utilizando la biblioteca de compatibilidad con versiones anteriores v7 (que probablemente debería).
fr4gus
8

Establecer Activityel título de un Fragmentdesordena los niveles de responsabilidad. Fragmentestá contenido dentro de Activity, por lo que este es el Activity, que debe establecer su propio título de acuerdo con el tipo de, Fragmentpor ejemplo.

Suponga que tiene una interfaz:

interface TopLevelFragment
{
    String getTitle();
}

Los Fragments que pueden influir en el Activitytítulo de entonces implementan esta interfaz. Mientras se encuentra en la actividad de alojamiento, escribe:

@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 esta manera, Activitysiempre se tiene el control de qué título usar, incluso si TopLevelFragmentse combinan varios , lo cual es bastante posible en una tableta.

Aleks N.
fuente
6

No creo que la respuesta aceptada sea la respuesta perfecta. Dado que todas las actividades que utilizan

Barra de herramientas

se extienden usando

AppCompatActivity

, los fragmentos llamados desde él pueden usar el código mencionado a continuación para cambiar el título.

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

En el Fragmento que podemos usar así, funciona bien para mí.

getActivity().getActionBar().setTitle("YOUR TITLE");
NagarjunaReddy
fuente
Esto no funciona cuando la barra de herramientas de nuestra actividad tiene un TextView que tiene el rol del título
Simon
4

En caso de que tenga problemas con el código, intente poner getSupportActionBar().setTitle(title)dentro onResume()de su fragmento en lugar de onCreateView(...)ie

En MainActivity.java :

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

En fragmento:

 @Override
 public void onResume(){
     super.onResume();
     ((MainActivity) getActivity()).setActionBarTitle("Your Title");
 }
realpac
fuente
Este era mi problema: dónde estaba poniendo el título. Sin embargo, fue ((MainActivity) getActivity()).setTitle("title")suficiente. En Kotlin, mi fragmento lo hace activity!!.title = "title.
Joe Lapp
2

Utilice lo siguiente:

getActivity().setTitle("YOUR_TITLE");
Anisetti Nagendra
fuente
Esta respuesta es para cambiar el título de la actividad, la pregunta es sobre el título de ActionBar.
David d C e Freitas
¡Gracias @Anisetti! Eso es exactamente lo que hice en la clase de Fragmento.
Francis Rodrigues
2

Aquí está mi solución para configurar el título de ActionBar a partir de fragmentos, cuando se usa NavigationDrawer. Esta solución utiliza una interfaz, por lo que los fragmentos no necesitan hacer referencia a la actividad principal directamente:

1) Cree una interfaz:

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

2) En onAttach del Fragmento, transmita la actividad al tipo de Interfaz y llame al método SetActivityTitle:

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

3) En la actividad, implemente la interfaz ActionBarTitleSetter :

@Override 
public void setTitle(String title) { 
    mTitle = title; 
}
Assaf S.
fuente
Esta debería ser la respuesta aceptada porque todos los demás enfoques hacen que el fragmento esté vinculado a una actividad particular, que no es un diseño escalable, también esto es lo que también recomienda el marco de Android
Akhil Dad
2

Mejor evento para cambiar de título 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
fuente
2

Un simple ejemplo de Kotlin

Suponiendo que estas deps de Gradle coincidan o sean una versión superior en su proyecto:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Adapte esto a sus clases de fragmentos:

    /**
     * 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
fuente
1

Si tiene una actividad principal con muchos fragmentos, generalmente usa el navigationDrawer. Y tienes una serie de títulos para tus fragmentos, cuando presionas atrás, para que cambien, pon esto en la actividad principal que contiene los fragmentos.

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

}

Esto supone que para cada fragmento le da una etiqueta, generalmente en algún lugar cuando agrega los fragmentos a la lista de navigationDrawer, de acuerdo con la posición presionada en la lista. Entonces esa posición es lo que capturo en la etiqueta:

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

Ahora, navMenuTitles es algo que carga en onCreate

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

La matriz xml es un recurso de cadena de tipo matriz en strings.xml

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

Guarde su respuesta en el objeto String [] y configúrelo en OnTabChange () en MainActivity como se muestra a continuaciónwww

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
fuente
1

La desventaja de tu enfoque de casting como tal

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

es que su fragmento ya no es reutilizable fuera de MainActivityFragment. Si no planea usarlo fuera de esa actividad, entonces no hay problema. Un mejor enfoque sería establecer condicionalmente el título en función de la actividad. Entonces, dentro de su fragmento, escribiría:

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

Si está utilizando la plantilla estable de Android Studio 1.4 proporcionada por Google, entonces debe escribir el siguiente código en el onNavigationItemSelectedmétodo en el que su fragmento relacionado llama a la condición.

 setTitle("YOUR FRAGMENT TITLE");
Manan Patel
fuente
eso es maravilloso si tiene acceso al título directamente desde la actividad ... pero si el título es una cadena establecida dinámicamente en el fragmento, debe haber comunicación entre el fragmento y la actividad
yo_
1

Obtengo una solución muy simple para configurar ActionBar Title en un fragmento o en cualquier actividad sin ningún dolor de cabeza.

Simplemente modifique el xml donde se define la barra de herramientas de la siguiente manera:

<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 desea configurar la barra de acciones en un fragmento, entonces:

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

Para usarlo desde cualquier lugar, puede definir un método en la actividad

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

Para llamar a este método en actividad, simplemente llámelo.

setActionBarTitle("Your Title")

Para llamar a este método desde un fragmento de la actividad, simplemente llámelo.

((MyActivity)getActivity()).setActionBarTitle("Your Title");
JoboFive
fuente
¡Excelente! El uso de toolbar_title anula el título del fragmento si usa componentes de navegación de Android.
Paixols
0

Solo para agregar a la respuesta seleccionada, es posible que también desee agregar un segundo método a su actividad principal. Entonces terminaría con los siguientes métodos en su actividad principal:

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

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

Esto le permitirá establecer el título tanto de una variable de cadena como de un ID de recurso, como el R.id.this_is_a_stringde su archivo strings.xml. Esto también funcionará un poco más como getSupportActionBar().setTitle()funciona, ya que le permite pasar un ID de recurso.

CodyEngel
fuente
0

Hay muchas formas como se describió anteriormente. También puede hacer esto onNavigationDrawerSelected()en suDrawerActivity

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);
    }
}
truco
fuente
0

Al menos para mí, hubo una respuesta fácil (después de mucho investigar) para cambiar el título de una pestaña en tiempo de ejecución:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos) .setText ("Mi nuevo texto");

marca
fuente
0

Si está usando ViewPager(como mi caso) puede usar:

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

en el onPageSelectedmétodo de tuVIEW_PAGER.addOnPageChangeListener

Reza
fuente
0

En su MainActivity, bajo onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Y en su actividad de fragmentos en onResume:

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

Opcional: - si muestran una advertencia de referencia nula

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


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