Установка пользовательского заголовка ActionBar из фрагмента

В моей главной FragmentActivityЯ настраиваю свой кастом ActionBar название как это:

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

Это работает отлично. Однако, как только я открою другой FragmentsЯ хочу, чтобы название изменилось. Я не уверен, как получить доступ к главному Activity сделать это? В прошлом я делал это:

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

Может кто-нибудь посоветовать правильный метод?

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>

22 ответа

Решение

В вашей деятельности:

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

И в вашем фрагменте:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    // Set title bar
    ((MainFragmentActivity) getActivity())
            .setActionBarTitle("Your title");

}

=== Обновление 10 апреля 2015 г. ===

Вы должны использовать слушатель, чтобы обновить заголовок панели действий

Фрагмент:

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

}

И активность:

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

}

Подробнее читайте здесь: https://developer.android.com/training/basics/fragments/communicating.html

То, что вы делаете, правильно. Fragments не имеют доступа к ActionBar API, поэтому вы должны позвонить getActivity, Если только ваш Fragment является статическим внутренним классом, в этом случае вы должны создать WeakReference к родителю и вызвать активность. getActionBar оттуда.

Чтобы установить заголовок для вашего ActionBar, используя пользовательский макет, в вашем Fragment вам нужно позвонить getActivity().setTitle(YOUR_TITLE),

Причина, по которой вы звоните setTitle потому что ты звонишь getTitle как название вашего ActionBar, getTitle возвращает заголовок для этого Activity,

Если вы не хотите, чтобы вам позвонили getTitle, тогда вам нужно будет создать публичный метод, который устанавливает текст вашего TextView в Activity где находится Fragment,

В вашей деятельности:

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

В вашем фрагменте:

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

Docs:

Activity.getTitle

Activity.setTitle

Кроме того, вам не нужно звонить this.whatever в коде, который вы предоставили, просто совет.

Примеры Google, как правило, используют это во фрагментах.

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

Фрагмент будет принадлежать ActionBarActivity, и именно там находится ссылка на панель действий. Это чище, потому что фрагменту не нужно точно знать, что это за действие, ему нужно только принадлежать действию, которое реализует ActionBarActivity. Это делает фрагмент более гибким и может быть добавлен к нескольким действиям так, как они предназначены.

Теперь все, что вам нужно сделать во фрагменте, это.

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

Это хорошо работает, если у вас есть базовый фрагмент, от которого наследуются ваши фрагменты вместо обычного класса фрагмента.

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

Тогда в вашем фрагменте.

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

Я не думаю, что принятый ответ является идеальным ответом на это. Поскольку все виды деятельности, которые используют

Панель инструментов

расширяются с помощью

AppCompatActivity

вызываемые из него фрагменты могут использовать указанный ниже код для изменения заголовка.

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

Простой пример Котлина

Предполагая, что эти градиентные зависимости совпадают или имеют более высокую версию в вашем проекте:

kotlin_version = '1.3.41'
nav_version_ktx = '2.0.0'

Адаптируйте это к своим классам фрагментов:

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


    }

Настройка Activityназвание от Fragment портит уровни ответственности. Fragment содержится в Activityтак что это Activity, который должен установить свой собственный заголовок в соответствии с типом Fragment например.

Предположим, у вас есть интерфейс:

interface TopLevelFragment
{
    String getTitle();
}

Fragmentкоторые могут влиять на ActivityЗатем реализуйте этот интерфейс. Во время хостинга вы пишете:

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

Таким образом Activity всегда контролирует, какой заголовок использовать, даже если несколько TopLevelFragments комбинируются, что вполне возможно на планшете.

Во фрагменте, который мы можем использовать следующим образом, он отлично работает для меня.

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

На всякий случай, если у вас возникли проблемы с кодом, попробуйте поставить getSupportActionBar().setTitle(title) внутри onResume() вашего фрагмента вместо onCreateView(...) т.е.

В MainActivity.java:

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

Во фрагменте:

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

Используйте следующее:

getActivity().setTitle("YOUR_TITLE");

Лучшее событие для смены названия 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);
}

Вот мое решение для установки заголовка ActionBar из фрагментов при использовании NavigationDrawer. В этом решении используется интерфейс, поэтому фрагментам не нужно напрямую ссылаться на родительское действие:

1) Создать интерфейс:

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

2) В onAttach фрагмента приведите действие к типу интерфейса и вызовите метод SetActivityTitle:

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

3) В упражнении реализуйте интерфейс ActionBarTitleSetter:

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

Если вы используете стабильный шаблон Android Studio 1.4, предоставляемый Google, чем просто, вы должны были написать следующий код в onNavigationItemSelected метод, в котором ваш связанный фрагмент вызывает условие if.

 setTitle("YOUR FRAGMENT TITLE");

Сохраните ваш ответ в объекте String[] и установите его OnTabChange() в MainActivity, как показано ниже

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

Недостаток вашего подхода к кастингу вот так

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

в том, что ваш фрагмент больше не может использоваться повторно вне MainActivityFragment. Если вы не планируете использовать его вне этой деятельности, то проблем нет. Лучшим подходом было бы условно установить заголовок в зависимости от вида деятельности. Итак, внутри вашего фрагмента вы бы написали:

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

Если у вас есть основной вид деятельности с множеством вставленных фрагментов, обычно с помощью navigationDrawer. И у вас есть массив названий для ваших фрагментов, когда вы нажимаете назад, чтобы они изменились, поместите это в основной акт, содержащий фрагменты

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

}

Это предполагает, что для каждого фрагмента вы назначаете ему тег, обычно где-то, когда вы добавляете фрагменты в список navigationDrawer, в соответствии с позицией, нажатой в списке. Так что это позиция, которую я фиксирую на теге:

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

Теперь navMenuTitles - это то, что вы загружаете в onCreate.

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

Массив xml является строковым ресурсом типа массива в strings.xml

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

Я получаю очень простое решение установить заголовок ActionBar в любом фрагменте или любой деятельности без головной боли.

Просто измените XML, где определена Панель инструментов, как показано ниже:

<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) Если вы хотите установить панель действий во фрагменте, то:

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

Чтобы использовать его из любого места, вы можете определить метод в деятельности

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

Чтобы вызвать этот метод в действии, просто вызовите его.

setActionBarTitle("Your Title")

Чтобы вызвать этот метод из фрагмента действия, просто вызовите его.

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

Есть много способов, как указано выше. Вы также можете сделать это в onNavigationDrawerSelected()в вашем DrawerActivity

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

Решение, основанное на ответе Ашиша с Java

      private void setUI(){
    mainToolbar = findViewById(R.id.mainToolbar);
    setSupportActionBar(mainToolbar);
    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    NavigationView navigationView = findViewById(R.id.nav_view);
    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_messaging, R.id.nav_me)
            .setDrawerLayout(drawer)
            .build();

    navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    navController.addOnDestinationChangedListener(navDestinationChange);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);
}

private NavController.OnDestinationChangedListener navDestinationChange = new NavController.OnDestinationChangedListener(){
    @Override
    public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
        if(R.id.nav_home==destination.getId()){
            destination.setLabel("News");
        }
    }
};

В вашей основной деятельности, под onCreate:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

А в твоем фрагменте активность под onResume:

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

Необязательно:- если они показывают предупреждение о нулевой ссылке

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


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

Просто чтобы добавить к выбранному ответу, вы также можете добавить второй метод к вашей основной деятельности. Таким образом, вы будете использовать следующие методы в своей основной деятельности:

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

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

Это позволит вам установить заголовок как из строковой переменной, так и из идентификатора ресурса, такого как R.id.this_is_a_string из вашего файла strings.xml. Это также будет работать немного больше как getSupportActionBar().setTitle() работает, поскольку позволяет передавать идентификатор ресурса.

По крайней мере, для меня был простой ответ (после долгих размышлений) на изменение названия вкладки во время выполнения:

TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); tabLayout.getTabAt (MyTabPos).setText ("Мой новый текст");

Если вы используете ViewPager (как и в моем случае) вы можете использовать:

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

в onPageSelected метод вашего VIEW_PAGER.addOnPageChangeListener

Другие вопросы по тегам