从 Fragment 设置自定义 ActionBar 标题
Posted
技术标签:
【中文标题】从 Fragment 设置自定义 ActionBar 标题【英文标题】:Setting Custom ActionBar Title from Fragment 【发布时间】:2013-03-11 18:03:38 【问题描述】:在我的 Main 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
,我希望更改标题。我不确定如何访问 Main 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_
android:layout_
android:background="@android:color/transparent" >
<TextView
android:id="@+id/title"
android:layout_
android:layout_
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:ellipsize="end"
android:maxLines="1"
android:text=""
android:textColor="#fff"
android:textSize="25sp" />
</RelativeLayout>
【问题讨论】:
***.com/a/28279341/1651286 应该是公认的答案,因为它具有可扩展性。因为所有其他方法都将片段绑定到特定的活动,这不是一个可扩展的设计,如果同一个片段必须用于多个活动怎么办,这也是 android 框架也推荐的。 看这个链接***.com/a/46705242/1770868 【参考方案1】:你所做的是正确的。 Fragments
无权访问 ActionBar
API,因此您必须调用 getActivity
。除非您的 Fragment
是静态内部类,在这种情况下,您应该为父级创建一个 WeakReference
并从那里调用 Activity.getActionBar
。
要为您的ActionBar
设置标题,同时使用自定义布局,您需要在您的Fragment
中调用getActivity().setTitle(YOUR_TITLE)
。
之所以调用setTitle
,是因为您调用getTitle
作为ActionBar
的标题。 getTitle
返回该 Activity
的标题。
如果您不想调用getTitle
,那么您需要创建一个公共方法,将TextView
的文本设置在承载Activity
的Activity
中。
在您的活动中:
public void setActionBarTitle(String title)
YOUR_CUSTOM_ACTION_BAR_TITLE.setText(title);
在您的片段中:
((MainFragmentActivity) getActivity()).setActionBarTitle(YOUR_TITLE);
文档:
Activity.getTitle
Activity.setTitle
另外,您无需在提供的代码中调用this.whatever
,只是一个提示。
【讨论】:
我尝试过,但无法正常工作。为了它的价值,我发布了我的XML
并删除了“this”。没有变化...不,它不是 static
内部类。
等等,什么不起作用?在您的 OP 中,您没有提及任何不起作用,您只提到想知道从Fragment
在ActionBar
中设置标题的“正确”方法。另外,我并没有提供删除 this.whatever
作为解决任何问题的方法,这只是一个代码格式提示。
我想我了解您遇到的问题并相应地编辑了我的答案。
感谢完美答案
@KickingLettuce,我在这个答案上挣扎了一段时间,直到我让它起作用(这就是我赞成它的原因,以及你的问题):在我的导航抽屉主要活动中(menu_act
)我创建了全局“mTitle”,并且在一个片段中,首先我为“mTitle”(( (menu_act) getActivity() ).mTitle = "new_title"
)分配了一个标题,然后立即执行( (menu_act) getActivity() ).restoreActionBar();
。在“restoreActionBar()”里面我有“actionBar.setTitle(mTitle);”。【参考方案2】:
===2019 年 10 月 30 日更新===
由于我们有了 ViewModel 和 LiveData 等新组件,我们可以通过使用 ViewModel 和 Live Data 以不同/更简单的方式从 Fragment 更新 Activity Title p>
活动
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
)
主片段
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")
还有 MainModelView:
class MainViewModel : ViewModel()
private val _title = MutableLiveData<String>()
val title: LiveData<String>
get() = _title
fun updateActionBarTitle(title: String) = _title.postValue(title)
然后您可以使用 viewModel.updateActionBarTitle("Custom Title From Fragment")
从 Fragment 更新 Activity 标题
===2015 年 4 月 10 日更新===
您应该使用监听器来更新您的操作栏标题
片段:
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
【讨论】:
它对我有用!我只是在活动中使用了 getActionBar().setTitle(title) 。谢谢 正是我想要的——对我来说比选择的答案更好。谢谢! 这应该是公认的答案!它正确地显示了它应该如何完成:如果一个片段想要与它的宿主活动通信,通信应该总是通过一个接口发生。片段提供接口,活动实现它!如果多个片段必须以相同的方式与一个活动进行通信,请编写一个提供接口的抽象片段,然后让每个片段都继承自这个“基础片段”。 顺便说一句:这个答案中使用的 onAttach(Activity) 方法此时已弃用。检查onAttach(Context)
方法内部传递的主机活动是否实现了所需的接口(通过context.getActivity()
检索主机活动)。
多年后我将其更改为公认的答案,因为我们知道,接口是片段和活动需要通信的方式。【参考方案3】:
Google 示例倾向于在片段中使用它。
private ActionBar getActionBar()
return ((ActionBarActivity) getActivity()).getSupportActionBar();
片段将属于一个 ActionBarActivity 并且是对 actionbar 的引用所在的位置。这样更简洁,因为片段不需要确切知道它是什么活动,它只需要属于实现了 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");
【讨论】:
谢谢。非常好的解决方案,通过这种方式,您还可以将自定义视图传递给您的操作栏。 随着 Android SDK 的最新更新,而不是 ActionBarActivity,您可能希望向下转换为 AppCompatActivity,以防您使用 v7 向后兼容库(您可能应该这样做)。【参考方案4】:我不认为接受的答案是完美的答案。由于所有使用
的活动工具栏
使用
扩展AppCompatActivity
,从中调用的片段可以使用下面提到的代码来更改标题。
((AppCompatActivity) context).getSupportActionBar().setTitle("Your Title");
【讨论】:
即使现在也能完美运行。谢谢!【参考方案5】:从Fragment
设置Activity
的标题会混淆责任级别。 Fragment
包含在Activity
中,所以这是Activity
,它应该根据Fragment
的类型设置自己的标题。
假设你有一个接口:
interface TopLevelFragment
String getTitle();
Fragment
s 可以影响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,这在平板电脑上是完全可能的。
【讨论】:
【参考方案6】:一个简单的 Kotlin 示例
将此适应您的片段类:
/**
* 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()
override fun onResume()
super.onResume()
(requireActivity() as MyMainActivity).supportActionBar?.title = "My Fragment!"
【讨论】:
【参考方案7】:在我们可以这样使用的片段中,它对我来说很好用。
getActivity().getActionBar().setTitle("YOUR TITLE");
【讨论】:
当我们activity的Toolbar有一个TextView具有title的作用时,这不起作用 @Simon 因为和setTitle()
没有关系,是自定义实现,需要自己处理【参考方案8】:
以防万一您遇到代码问题,请尝试将 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");
【讨论】:
这是我的问题——在哪里我设置了标题。但是,((MainActivity) getActivity()).setTitle("title")
就足够了。在 Kotlin 中,我的片段是 activity!!.title = "title
。【参考方案9】:
使用以下内容:
getActivity().setTitle("YOUR_TITLE");
【讨论】:
这个答案是改变Activity的标题,问题是关于ActionBar的标题。 谢谢@Anisetti!这正是我在 Fragment 课上所做的。【参考方案10】:这是我在使用 NavigationDrawer 时从片段设置 ActionBar 标题的解决方案。 该解决方案使用接口,因此片段不需要直接引用父 Activity:
1) 创建接口:
public interface ActionBarTitleSetter
public void setTitle(String title);
2)在Fragment的onAttach中,将activity转换为Interface类型并调用SetActivityTitle方法:
@Override
public void onAttach(Activity activity)
super.onAttach(activity);
((ActionBarTitleSetter) activity).setTitle(getString(R.string.title_bubbles_map));
3) 在activity中,实现ActionBarTitleSetter接口:
@Override
public void setTitle(String title)
mTitle = title;
【讨论】:
这应该是公认的答案,因为所有其他方法都使片段与特定活动相关联,这不是可扩展的设计,这也是 android 框架也推荐的【参考方案11】:更改标题的最佳事件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);
【讨论】:
【参考方案12】:如果您有一个包含许多片段的主要活动,通常使用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>
【讨论】:
【参考方案13】:将您的答案保存在 String[] 对象中,并在 MainActivity 中将其设置为 OnTabChange() 如下www
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));
【讨论】:
【参考方案14】:你这样铸造方法的缺点
((MainFragmentActivity) getActivity()).getSupportActionBar().setTitle(
catTitle);
是您的片段在 MainActivityFragment 之外不再可重用。如果您不打算在该活动之外使用它,那么没有问题。更好的方法是根据活动有条件地设置标题。所以在你的片段中,你会写:
if (getActivity() instanceof ActionBarActivity)
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Some Title");
【讨论】:
【参考方案15】:如果您使用的是 google 提供的 android studio 1.4 stable 模板,那么您必须在 onNavigationItemSelected
methode 中编写以下代码
您的相关片段在其中调用 if 条件。
setTitle("YOUR FRAGMENT TITLE");
【讨论】:
如果您可以直接从活动中访问标题,那就太好了......但是如果标题是片段中动态设置的字符串,则片段和活动之间需要进行通信【参考方案16】:我得到了一个非常简单的解决方案来设置 ActionBar Title 片段或任何活动都不会让人头疼。
只需修改定义工具栏的xml如下:
<android.support.design.widget.AppBarLayout
android:layout_
android:layout_
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
android:background="@color/colorPrimaryDark"
app:popupTheme="@style/AppTheme.PopupOverlay" >
<TextView
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:id="@+id/toolbar_title"
android:layout_
android:layout_
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");
【讨论】:
太棒了!如果使用 Android 导航组件,则使用 toolbar_title 会覆盖片段标题。【参考方案17】:只是为了添加到选定的答案,您可能还想在主要活动中添加第二种方法。所以你最终会在你的主要活动中使用以下方法:
public void setActionBarTitle(String title)
getSupportActionBar().setTitle(title);
public void setActionBarTitle(int resourceId)
setActionBarTitle(getResources().getString(resourceId);
这将允许您从 String 变量以及资源 ID(例如 strings.xml 文件中的R.id.this_is_a_string
)设置标题。这也将更像getSupportActionBar().setTitle()
的工作方式,因为它允许您传入资源 ID。
【讨论】:
【参考方案18】:如上所述,有很多方法。您也可以在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);
【讨论】:
【参考方案19】:至少对我来说,在运行时更改标签标题有一个简单的答案(经过大量挖掘):
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.getTabAt(MyTabPos).setText("我的新文本");
【讨论】:
【参考方案20】:如果您使用ViewPager
(如我的情况),您可以使用:
getSupportActionBar().setTitle(YOURE_TAB_BAR.getTabAt(position).getText());
在您的VIEW_PAGER.addOnPageChangeListener
的onPageSelected
方法中
【讨论】:
【参考方案21】:在您的 MainActivity 中,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);
【讨论】:
【参考方案22】:基于 Ashish 的 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");
;
【讨论】:
以上是关于从 Fragment 设置自定义 ActionBar 标题的主要内容,如果未能解决你的问题,请参考以下文章
Android Date Picker Fragment 不能设置为自定义日期