Установка пользовательского заголовка 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
всегда контролирует, какой заголовок использовать, даже если несколько TopLevelFragment
s комбинируются, что вполне возможно на планшете.
Во фрагменте, который мы можем использовать следующим образом, он отлично работает для меня.
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");
}
Лучшее событие для смены названия 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