Ustawianie niestandardowego tytułu ActionBar z fragmentu


90

W moim menu głównym FragmentActivitykonfiguruję ActionBartytuł niestandardowy w następujący sposób:

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

To działa idealnie. Jednak gdy otworzę inne Fragments, chcę zmienić tytuł. Nie jestem pewien, jak uzyskać dostęp do strony głównej, Activityaby to zrobić? W przeszłości robiłem to:

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

Czy ktoś może doradzić właściwą metodę?

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 powinien być akceptowaną odpowiedzią ze względu na jego skalowalność. ponieważ wszystkie inne podejścia powodują, że fragment jest powiązany z konkretną aktywnością, co nie jest skalowalnym projektem, a co jeśli ten sam fragment ma być używany z wieloma działaniami, również to zaleca framework Android.
Akhil Dad

Odpowiedzi:


98

=== Aktualizacja, 30 października 2019 r. ===

Ponieważ mamy nowe komponenty, takie jak ViewModel i LiveData , możemy mieć inny / łatwiejszy sposób aktualizowania tytułu działania z fragmentu za pomocą ViewModel i Live Data

Czynność

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

Oraz MainModelView:

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

Następnie możesz zaktualizować tytuł działania z Fragment za pomocą viewModel.updateActionBarTitle("Custom Title From Fragment")

=== Aktualizacja, 10 kwietnia 2015 ===

Do aktualizacji tytułu paska akcji należy użyć listenera

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

I aktywność:

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

Przeczytaj więcej tutaj: https://developer.android.com/training/basics/fragments/communicating.html


1
U mnie zadziałało! Po prostu użyłem getActionBar (). SetTitle (tytuł) zamiast w działaniu. Dzięki
luckyreed76

1
Dokładnie to, czego szukałem - działało lepiej dla mnie niż wybrana odpowiedź. Dzięki!
dstrube

1
To powinna być akceptowana odpowiedź! Prawidłowo pokazuje, jak należy to zrobić: Jeśli fragment chce komunikować się ze swoją aktywnością hostingową, komunikacja powinna zawsze odbywać się za pośrednictwem interfejsu. Fragment zapewnia interfejs, a działanie go implementuje! Jeśli wiele fragmentów musi komunikować się w ten sam sposób z działaniem, napisz abstrakcyjny fragment, który zapewnia interfejs, a następnie pozwól, aby każdy fragment odziedziczył po tym „podstawowym fragmencie”.
winklerrr

3
Przy okazji: metoda onAttach (Activity) użyta w tej odpowiedzi jest do tego czasu przestarzała. Sprawdź wewnątrz onAttach(Context)metody, czy przekazana aktywność hosta implementuje wymagany interfejs (pobierz aktywność hosta za pośrednictwem context.getActivity()).
winklerrr

2
Po wielu latach zmieniłem to na akceptowaną odpowiedź, ponieważ jak wiemy, interfejsy to sposób, w jaki fragmenty i działania muszą się komunikować.
TheLettuceMaster

150

To, co robisz, jest poprawne. Fragmentsnie masz dostępu do ActionBarinterfejsów API, więc musisz zadzwonić getActivity. O ile twoja nie Fragmentjest statyczną klasą wewnętrzną, w takim przypadku powinieneś utworzyć WeakReferencedo rodzica i wywołać Activity. getActionBarstamtąd.

Aby ustawić tytuł dla swojego ActionBar, korzystając z niestandardowego układu, Fragmentmusisz zadzwonić getActivity().setTitle(YOUR_TITLE).

Powodem, dla którego dzwonisz, setTitlejest to, że dzwonisz getTitlejako tytuł swojego ActionBar. getTitlezwraca tytuł tego Activity.

Jeśli nie chcesz odbierać połączenia getTitle, musisz utworzyć publiczną metodę, która ustawia tekst twojego TextVieww Activityhostującym Fragment.

W Twojej aktywności :

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

W swoim fragmencie :

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

Dokumenty:

Activity.getTitle

Activity.setTitle

Nie musisz też wywoływać this.whateverpodanego kodu, wystarczy napiwek.


Próbuję i nie mogę zmusić tego do pracy. Na ile to warte, opublikowałem moje XMLi również usunąłem „to”. Bez zmian ... I nie, to nie jest staticklasa wewnętrzna.
TheLettuceMaster

Czekaj, co nie działa? W swoim OP nie wspominasz o niczym nie działającym, wspominasz tylko o tym, że chcesz znać "właściwą" metodę ustawiania tytułu w ActionBarpliku z pliku Fragment. Ponadto nie oferowałem usuwania this.whateverjako rozwiązania czegokolwiek, to była tylko wskazówka dotycząca formatowania kodu.
adneal

Myślę, że rozumiem, z czym masz problem, i odpowiednio zredagowałem moją odpowiedź.
adneal

Dziękuję idealna odpowiedź
Ammar ali

@KickingLettuce, przez chwilę zmagam się z tą odpowiedzią, dopóki nie zadziałała (dlatego zagłosowałem za nią, podobnie jak twoje pytanie): w mojej głównej aktywności w szufladzie nawigacji ( menu_act) stworzyłem globalny „mTitle” i fragment, najpierw przypisuję tytuł do „mTitle” ( ( (menu_act) getActivity() ).mTitle = "new_title") i od razu to robię ( (menu_act) getActivity() ).restoreActionBar();. Wewnątrz "restoreActionBar ()" mam "actionBar.setTitle (mTitle);".
Jose Manuel Abarca Rodríguez

29

Przykłady Google zwykle używają tego we fragmentach.

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

Fragment będzie należał do ActionBarActivity i tam znajduje się odniesienie do paska akcji. Jest to czystsze, ponieważ fragment nie musi dokładnie wiedzieć, jakie to jest działanie, musi tylko należeć do działania, które implementuje ActionBarActivity. To sprawia, że ​​fragment jest bardziej elastyczny i można go dodać do wielu działań, tak jak powinien.

Teraz wszystko, co musisz zrobić we fragmencie, to.

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

Działa to dobrze, jeśli masz fragment podstawowy, z którego dziedziczą Twoje fragmenty zamiast normalnej klasy fragmentów.

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

Następnie w swoim fragmencie.

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

Dzięki. bardzo fajne rozwiązanie, w ten sposób możesz również przekazać własny widok do paska akcji.
Amir

Dzięki niedawnym aktualizacjom w Android SDK zamiast ActionBarActivity możesz chcieć obniżyć do AppCompatActivity w przypadku, gdy używasz biblioteki kompatybilności wstecznej v7 (co prawdopodobnie powinieneś).
fr4gus

8

Ustawienie Activitytytułu z Fragmentpomieszania poziomów odpowiedzialności. Fragmentjest zawarty w elemencie Activity, więc to jest Activity, który powinien ustawić własny tytuł zgodnie z typem Fragmentna przykład.

Załóżmy, że masz interfejs:

interface TopLevelFragment
{
    String getTitle();
}

Te, Fragmentktóre mogą mieć wpływ na Activitytytuł, implementują ten interfejs. Prowadząc działalność hostingową piszesz:

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

W ten sposób Activityzawsze TopLevelFragmentmasz kontrolę nad tym, jakiego tytułu użyć, nawet jeśli łączy się kilka tytułów , co jest całkiem możliwe na tablecie.


6

Nie sądzę, aby zaakceptowana odpowiedź była na to doskonałą odpowiedzią. Ponieważ wszystkie czynności, które używają

pasek narzędzi

są przedłużane za pomocą

AppCompatActivity

, wywołane z niej fragmenty mogą użyć poniższego kodu do zmiany tytułu.

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

5

We fragmencie, którego możemy użyć w ten sposób, działa dobrze dla mnie.

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

To nie działa, gdy Toolbar naszej aktywności ma TextView, który ma rolę tytułu
Simon

4

Na wszelki wypadek, jeśli masz problemy z kodem, spróbuj umieścić getSupportActionBar().setTitle(title)wewnątrz onResume()swojego fragmentu zamiast onCreateView(...)np

W MainActivity.java :

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

Fragmentowo:

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

To był mój problem - gdzie ustawiałem tytuł. Jednak ((MainActivity) getActivity()).setTitle("title")wystarczyło. W Kotlinie mój fragment tak activity!!.title = "title.
Joe Lapp


2

Oto moje rozwiązanie do ustawiania tytułu ActionBar z fragmentów podczas korzystania z NavigationDrawer. To rozwiązanie używa interfejsu, więc fragmenty nie muszą bezpośrednio odwoływać się do działania nadrzędnego:

1) Utwórz interfejs:

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

2) W onAttach fragmentu rzutuj działanie na typ Interface i wywołaj metodę SetActivityTitle:

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

3) W działaniu zaimplementuj ActionBarTitleSetter interfejs :

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

Powinna to być akceptowana odpowiedź, ponieważ wszystkie inne podejścia tworzą fragment związany z konkretną aktywnością, co nie jest skalowalnym projektem, również to, co również zaleca framework androida
Akhil Dad

2

Najlepsze wydarzenie dla zmiany tytułu 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

Prosty przykład Kotlina

Zakładając, że te deps gradle pasują do twojego projektu lub są w wyższej wersji:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Dostosuj to do swoich klas fragmentów:

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

Jeśli masz główne zadanie z wieloma fragmentami, które wstawiłeś, zwykle za pomocą navigationDrawer. I masz szereg tytułów dla swoich fragmentów, kiedy naciskasz, aby je zmienić, umieść to w głównym akcie, który zawiera fragmenty

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

}

Zakłada się, że każdemu fragmentowi nadajesz mu tag, zwykle gdzieś, kiedy dodajesz fragmenty do listy navigationDrawer, zgodnie z pozycją wciśniętą na liście. Więc ta pozycja jest tym, co przechwytuję na tagu:

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

Teraz navMenuTitles jest czymś, co ładujesz w pliku onCreate

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

Tablica xml jest zasobem ciągu typu tablica w strings.xml

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

1

Zapisz odpowiedź ur w obiekcie String [] i ustaw ją OnTabChange () w MainActivity jak poniżejwww

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

Wadą twojego podejścia do rzucania w ten sposób

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

polega na tym, że Twój fragment nie nadaje się już do ponownego użycia poza MainActivityFragment. Jeśli nie planujesz używać go poza tą aktywnością, nie ma problemu. Lepszym podejściem byłoby warunkowe ustawienie tytułu w zależności od czynności. Więc wewnątrz swojego fragmentu napisałbyś:

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

1

jeśli używasz stabilnego szablonu Android Studio 1.4 dostarczonego przez Google niż prosty, musisz napisać następujący kod w onNavigationItemSelectedmetodzie, w której Twój powiązany fragment wywołuje warunek if.

 setTitle("YOUR FRAGMENT TITLE");

to wspaniale, jeśli masz dostęp do tytułu bezpośrednio z działania ... ale jeśli tytuł jest dynamicznie ustawianym ciągiem we fragmencie, musi być komunikacja między fragmentem a działaniem
me_

1

Otrzymuję bardzo proste rozwiązanie, aby ustawić tytuł ActionBar w dowolnym fragmencie lub w dowolnej aktywności bez bólu głowy.

Po prostu zmodyfikuj xml, gdzie jest zdefiniowany pasek narzędzi, jak poniżej:

<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) Jeśli chcesz ustawić pasek akcji we fragmencie, to:

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

Aby używać go z dowolnego miejsca, możesz zdefiniować metodę w działaniu

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

Aby wywołać tę metodę w działaniu, po prostu ją wywołaj.

setActionBarTitle("Your Title")

Aby wywołać tę metodę z fragmentu aktywności, po prostu ją wywołaj.

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

Świetny! Użycie toolbar_title powoduje nadpisanie tytułu fragmentu, jeśli używasz składników nawigacji systemu Android.
Paixols

0

Aby dodać do wybranej odpowiedzi, możesz również dodać drugą metodę do głównego zadania. Więc skończyłbyś z następującymi metodami w swojej głównej działalności:

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

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

Umożliwi to ustawienie tytułu zarówno na podstawie zmiennej typu String, jak i identyfikatora zasobu, na przykład R.id.this_is_a_stringz pliku strings.xml. Będzie to również działać trochę bardziej tak, jak getSupportActionBar().setTitle()działa, ponieważ umożliwia przekazanie identyfikatora zasobu.


0

Jak opisano powyżej, istnieje wiele sposobów. Możesz to również zrobić onNavigationDrawerSelected()w swoimDrawerActivity

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

Przynajmniej dla mnie istniała łatwa odpowiedź (po wielu poszukiwaniach) na zmianę tytułu karty w czasie wykonywania:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos) .setText ("Mój nowy tekst");


0

Jeśli używasz ViewPager(jak mój przypadek), możesz użyć:

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

w onPageSelectedswojej metodzieVIEW_PAGER.addOnPageChangeListener


0

W Twojej MainActivity pod onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

A w Twojej działalności fragmentowej pod onResume:

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

Opcjonalnie: - jeśli pokazują ostrzeżenie o zerowym odwołaniu

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


Objects.requireNonNull(getActivity()).setTitle(R.string.app_name_science);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.