Definindo título de ActionBar personalizado a partir do fragmento

90

No meu Main FragmentActivity, eu configurei meu ActionBartítulo personalizado assim:

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

Isso funciona perfeitamente. No entanto, depois de abrir outro Fragments, quero que o título mude. Não tenho certeza de como acessar o Main Activitypara fazer isso? No passado, eu fazia isso:

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

Alguém pode aconselhar sobre o método adequado?

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
fonte
stackoverflow.com/a/28279341/1651286 deve ser a resposta aceita devido à sua escalabilidade. porque todas as outras abordagens estão criando fragmentos vinculados a uma atividade particular, que não é um design escalável, e se o mesmo fragmento tiver que ser usado com várias atividades, também é isso que o framework android também recomenda.
Akhil Dad
Olhe este link stackoverflow.com/a/46705242/1770868
Ahmad Aghazadeh

Respostas:

98

=== Atualização em 30 de outubro de 2019 ===

Como temos novos componentes, como ViewModel e LiveData , podemos ter uma maneira diferente / mais fácil de atualizar Activity Title de Fragment usando ViewModel e Live Data

Atividade

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

E então você pode atualizar o título da atividade do Fragment usando viewModel.updateActionBarTitle("Custom Title From Fragment")

=== Atualização de 10 de abril de 2015 ===

Você deve usar o listener para atualizar o título da barra de ação

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

E atividade:

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

Leia mais aqui: https://developer.android.com/training/basics/fragments/communicating.html

Frank Nguyen
fonte
1
Funcionou para mim! Acabei de usar getActionBar (). SetTitle (title) em vez da atividade. Obrigado
luckyreed76
1
Exatamente o que eu estava procurando funcionou melhor para mim do que a resposta escolhida. Obrigado!
dstrube
1
Esta deve ser a resposta aceita! Mostra corretamente como deve ser feito: Se um fragmento deseja se comunicar com sua atividade de hosting, a comunicação deve sempre acontecer por meio de uma interface. O fragmento fornece a interface e a atividade a implementa! Se vários fragmentos tiverem que se comunicar da mesma forma com uma atividade, escreva um fragmento abstrato que forneça a interface e, em seguida, deixe cada fragmento herdar desse "fragmento de base".
winklerrr de
3
A propósito: o método onAttach (Activity) usado nesta resposta está obsoleto neste momento. Verifique dentro do onAttach(Context)método se a atividade do host passada implementa a interface necessária (recuperar a atividade do host via context.getActivity()).
winklerrr de
2
Depois de muitos anos, mudei para a resposta aceita porque, como sabemos, as interfaces são a maneira como os fragmentos e as atividades precisam se comunicar.
TheLettuceMaster de
150

O que você está fazendo está correto. Fragmentsnão tem acesso às ActionBarAPIs, então você precisa chamar getActivity. A menos que Fragmentseja uma classe interna estática, nesse caso você deve criar um WeakReferencepara o pai e chamar Activity. getActionBarde lá.

Para definir o título do seu ActionBar, ao usar um layout personalizado, Fragmentvocê precisará chamar getActivity().setTitle(YOUR_TITLE).

A razão de você ligar setTitleé porque você está ligando getTitlecomo o título de seu ActionBar. getTitleretorna o título para isso Activity.

Se você não quiser receber uma chamada getTitle, precisará criar um método público que defina o texto do seu TextViewno Activityque hospeda o Fragment.

Em sua atividade :

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

Em seu fragmento :

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

Docs:

Activity.getTitle

Activity.setTitle

Além disso, você não precisa chamar this.whatevero código fornecido, apenas uma dica.

adneal
fonte
Eu tento e não consigo fazer funcionar. Por que vale a pena, eu postei meu XMLe também removi "este". Sem alterações ... E não, não é uma staticclasse interna.
TheLettuceMaster
Espere, o que não funciona? No seu OP você não menciona nada que não esteja funcionando, apenas menciona o desejo de saber o método "adequado" para definir o título no ActionBarde a Fragment. Além disso, eu não estava oferecendo a remoção this.whatevercomo solução para nada, era apenas uma dica de formatação de código.
adneal
Acho que entendi com que você está tendo problemas e editei minha resposta de acordo.
adneal
Obrigado, resposta perfeita
Ammar ali
@KickingLettuce, luto com essa resposta por um tempo até que ela funcione (é por isso que votei a favor, assim como sua pergunta): na atividade principal da minha gaveta de navegação ( menu_act) fiz "mTitle" global e, em um fragmento, primeiro atribuo um título a "mTitle" ( ( (menu_act) getActivity() ).mTitle = "new_title"), e imediatamente o faço ( (menu_act) getActivity() ).restoreActionBar();. Dentro de "restoreActionBar ()" eu tenho "actionBar.setTitle (mTitle);".
Jose Manuel Abarca Rodríguez
29

Os exemplos do Google tendem a usar isso nos fragmentos.

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

O fragmento pertencerá a uma ActionBarActivity e é aí que está a referência à actionbar. Isso é mais limpo porque o fragmento não precisa saber exatamente qual atividade é, ele só precisa pertencer a uma atividade que implemente ActionBarActivity. Isso torna o fragmento mais flexível e pode ser adicionado a várias atividades como deveriam.

Agora, tudo que você precisa fazer no fragmento é.

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

Isso funciona bem se você tiver um fragmento de base do qual seus fragmentos herdam em vez da classe de fragmento normal.

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

Então, em seu fragmento.

public class YourFragment extends BaseFragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getActionBar().setTitle("Your Title");
    }
}
Kalel Wade
fonte
Obrigado. solução muito boa, desta forma você também pode passar a visualização personalizada para sua barra de ação.
Amir de
Com atualizações recentes no Android SDK, em vez de ActionBarActivity, você pode querer fazer downcast para AppCompatActivity caso esteja usando a biblioteca de compatibilidade com versões anteriores da v7 (o que provavelmente deveria ser feito).
fr4gus
8

Definir Activityo título de uma Fragmentbagunça os níveis de responsabilidade. Fragmentestá contido em um Activity, então este é o Activity, que deve definir seu próprio título de acordo com o tipo de Fragmentpor exemplo.

Suponha que você tenha uma interface:

interface TopLevelFragment
{
    String getTitle();
}

Os Fragments que podem influenciar o Activitytítulo de então implementam essa interface. Durante a atividade de hospedagem, você escreve:

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

Desta forma, Activityestá sempre no controle de qual título usar, mesmo se vários TopLevelFragments forem combinados, o que é perfeitamente possível em um tablet.

Aleks N.
fonte
6

Não acho que a resposta aceita seja uma resposta perfeita para isso. Uma vez que todas as atividades que usam

Barra de ferramentas

são estendidos usando

AppCompatActivity

, os fragmentos chamados a partir dele podem usar o código mencionado abaixo para alterar o título.

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

No Fragment podemos usar assim, está funcionando bem para mim.

getActivity().getActionBar().setTitle("YOUR TITLE");
NagarjunaReddy
fonte
Isso não funciona quando a barra de ferramentas de nossa atividade tem um TextView que tem a função do título
Simon
4

Apenas no caso, se você está tendo problemas com o código, tente colocar getSupportActionBar().setTitle(title)dentro onResume()do seu fragmento em vez de onCreateView(...)ie

Em MainActivity.java :

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

Em Fragmento:

 @Override
 public void onResume(){
     super.onResume();
     ((MainActivity) getActivity()).setActionBarTitle("Your Title");
 }
Realpac
fonte
Esse era o meu problema - onde eu estava definindo o título. No entanto, ((MainActivity) getActivity()).setTitle("title")bastou. Em Kotlin, meu fragmento sim activity!!.title = "title.
Joe Lapp
2

Use o seguinte:

getActivity().setTitle("YOUR_TITLE");
Anisetti Nagendra
fonte
Esta resposta é para mudar o título da Activity, a pergunta é sobre o título da ActionBar.
David d C e Freitas
Obrigado @Anisetti! Isso é exatamente o que eu fiz na classe Fragment.
Francis Rodrigues
2

Aqui está minha solução para definir o título da ActionBar a partir de fragmentos, ao usar o NavigationDrawer. Esta solução usa uma interface para que os fragmentos não precisem fazer referência à atividade pai diretamente:

1) Crie uma interface:

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

2) No onAttach do Fragment , lance a atividade para o tipo de interface e chame o método SetActivityTitle:

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

3) Na atividade, implemente a interface ActionBarTitleSetter :

@Override 
public void setTitle(String title) { 
    mTitle = title; 
}
Assaf S.
fonte
Essa deve ser a resposta aceita porque todas as outras abordagens estão criando um fragmento vinculado a uma atividade específica, que não é um design escalonável, também é isso que o framework Android também recomenda
Akhil Dad
2

Melhor evento para mudar o 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
fonte
2

Um exemplo simples de Kotlin

Supondo que essas dependências gradle correspondam ou sejam uma versão superior em seu projeto:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Adapte isso às suas classes de fragmento:

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

Se você tem uma atividade principal com muitos fragmentos inseridos, geralmente usando o navigationDrawer. E você tem uma série de títulos para seus fragmentos, quando você pressiona para trás, para que eles mudem, coloque isso na atividade principal que contém os 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();
      }

}

Isso pressupõe que para cada fragmento você dê a ele uma tag, geralmente em algum lugar quando você adiciona os fragmentos à lista do navigationDrawer, de acordo com a posição pressionada na lista. Portanto, essa posição é o que capturo na tag:

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

Agora, o navMenuTitles é algo que você carrega no onCreate

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

O array xml é um recurso de string do tipo array em strings.xml

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

Salve sua resposta no objeto String [] e defina-o OnTabChange () em MainActivity como 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));
}
Narendra Kumar
fonte
1

A desvantagem de sua abordagem de elenco assim

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

é que seu fragmento não pode mais ser reutilizado fora de MainActivityFragment. Se você não planeja usá-lo fora dessa atividade, não há problema. Uma abordagem melhor seria definir condicionalmente o título, dependendo da atividade. Portanto, dentro do seu fragmento, você escreveria:

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

Se você estiver usando o modelo estável do Android Studio 1.4 fornecido pelo Google, do que simples, você terá que escrever o seguinte código no onNavigationItemSelectedmétodo em que seu fragmento relacionado chama se condição.

 setTitle("YOUR FRAGMENT TITLE");
Manan Patel
fonte
isso é maravilhoso se você tiver acesso ao título diretamente da atividade ... mas se o título for uma string definida dinamicamente no fragmento, deve haver comunicação entre o fragmento e a atividade
me_
1

Estou recebendo uma solução muito simples para definir o título da ActionBar em qualquer fragmento ou qualquer atividade sem qualquer dor de cabeça.

Apenas modifique o xml onde está definido a Barra de Ferramentas conforme abaixo:

<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 você deseja definir a barra de ação em um fragmento:

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

Para usá-lo de qualquer lugar, você pode definir um método na atividade

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

Para chamar este método em atividade, basta chamá-lo.

setActionBarTitle("Your Title")

Para chamar esse método a partir de um fragmento da atividade, basta chamá-lo.

((MyActivity)getActivity()).setActionBarTitle("Your Title");
JoboFive
fonte
Excelente! Usar o toolbar_title sobrescreve o título do fragmento se estiver usando Componentes de Navegação Android.
Paixols de
0

Apenas para adicionar na resposta selecionada, você também pode querer adicionar um segundo método à sua atividade principal. Então, você acabaria com os seguintes métodos em sua atividade principal:

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

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

Isso permitirá que você defina o título de uma variável String, bem como um ID de recurso, como R.id.this_is_a_stringdo arquivo strings.xml. Isso também funcionará um pouco mais como getSupportActionBar().setTitle()funciona, pois permite que você passe um ID de recurso.

CodyEngel
fonte
0

Existem muitas maneiras, conforme descrito acima. Você também pode fazer isso onNavigationDrawerSelected()em seuDrawerActivity

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);
    }
}
truque
fonte
0

Pelo menos para mim, houve uma resposta fácil (depois de muito pesquisar) para alterar o título de uma guia em tempo de execução:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos) .setText ("Meu Novo Texto");

Marca
fonte
0

Se você estiver usando ViewPager(como meu caso), você pode usar:

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

no onPageSelectedmétodo do seuVIEW_PAGER.addOnPageChangeListener

Reza
fonte
0

Em sua MainActivity, em onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

E em sua atividade de fragmento em onResume:

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

Opcional: - se mostrarem aviso de referência nula

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


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