从片段设置自定义ActionBar标题


90

在我的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);

这很完美。但是,一旦我打开other Fragments,我想更改标题。我不确定如何访问MainActivity来执行此操作?过去,我这样做:

((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>

由于其可扩展性,stackoverflow.com / a / 28279341/1651286应该是公认的答案。因为所有其他方法都将片段绑定到特定活动,而这不是可伸缩的设计,所以如果必须将同一片段用于多个活动该怎么办,这也是android框架所建议的。
阿希尔·爸爸

Answers:


98

===更新2019年10月30日===

由于我们有新的组件,例如ViewModelLiveData,因此可以使用ViewModel和Live Data通过一种不同/更简便的方式从Fragment更新活动标题

活动

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

然后您可以使用来更新Fragment中的Activity标题 viewModel.updateActionBarTitle("Custom Title From Fragment")

===更新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


1
它为我工作!我只是在活动中使用了getActionBar()。setTitle(title)。谢谢
luckyreed76

1
确实,我要找的东西比选择的答案对我来说更好。谢谢!
dstrube '16

1
这应该是公认的答案!它正确显示了应如何执行:如果片段想与其托管活动进行通信,则通信应始终通过接口进行。该片段提供了接口,活动将实现它!如果多个片段必须与活动以相同的方式进行通信,请编写一个提供接口的抽象片段,然后让每个片段都从该“基本片段”继承。
winklerrr

3
顺便说一句:这次不建议使用此答案中的onAttach(Activity)方法。检查onAttach(Context)所传递的主机活动是否实现了所需的接口的方法(通过检索主机活动context.getActivity())。
winklerrr

2
多年后,我将其更改为可接受的答案,因为众所周知,接口是片段和活动进行交流的方式。
TheLettuceMaster

150

你在做什么是对的。Fragments没有访问ActionBarAPI的权限,因此您必须致电getActivity。除非您Fragment是静态内部类,否则您应该WeakReference为父级创建一个并调用Activity。getActionBar从那里。

ActionBar在使用自定义布局时为您设置标题,您Fragment需要调用getActivity().setTitle(YOUR_TITLE)

你打电话的原因setTitle是因为你打电话getTitle为你的标题ActionBargetTitle返回该标题Activity

如果你不想让通话getTitle,那么你就需要创建一个公共方法,设置你的文字TextViewActivity承载Fragment

在您的活动中

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内部类。
TheLettuceMaster 2013年

等等,什么不起作用?在你的OP你不提什么工作,你只提想知道“正确”的方法来设置标题中ActionBar的一个Fragment。另外,我没有提供删除this.whatever作为任何解决方案的方法,那只是代码格式化技巧。
adneal

我想我了解您遇到的问题,并据此编辑了我的答案。
adneal

Thankx完美答案
Ammar ali 2015年

@KickingLettuce,我花了一段时间才解决这个问题,直到我使它起作用(这就是为什么我对它以及您的问题都表示赞成):在我的导航抽屉主活动(menu_act)中,我创建了全局“ mTitle”,并且在片段,首先我给“ mTitle”(( (menu_act) getActivity() ).mTitle = "new_title")分配一个标题,然后立即这样做( (menu_act) getActivity() ).restoreActionBar();。在“ restoreActionBar()”内部,我具有“ actionBar.setTitle(mTitle);”。
Jose Manuel AbarcaRodríguez2015年

29

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

谢谢。非常好的解决方案,通过这种方式,您还可以将自定义视图传递到操作栏。
阿米尔2015年

对于Android SDK的最新更新,而不是ActionBarActivity,如果您使用的是v7向后兼容库(您应该这样做),则可能希望向下转换为AppCompatActivity。
fr4gus

8

ActivityFragment混乱中设置的标题会弄乱责任级别。Fragment包含在中Activity,因此是Activity,应根据的类型设置自己的标题Fragment

假设您有一个接口:

interface TopLevelFragment
{
    String getTitle();
}

Fragment能够影响的SActivity的标题则实现此接口。在托管活动中,您将编写:

@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组合在一起,以这种方式始终可以控制要使用的标题,这在平板电脑上是很可能的。


6

我认为接受的答案不是完美的答案。由于所有使用的活动

工具列

扩展使用

AppCompatActivity

,从中调用的片段可以使用下面提到的代码来更改标题。

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

5

在Fragment中,我们可以像这样使用,对我来说很好。

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

当我们活动的工具栏上有一个具有标题角色的TextView时,这将不起作用
Simon

4

以防万一,如果您有代码的问题,可以尝试在 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")足够了。在科特林,我的片段是activity!!.title = "title
乔·拉普


2

这是我使用NavigationDrawer时从片段设置ActionBar标题的解决方案。此解决方案使用接口,因此片段无需直接引用父活动:

1)创建一个接口:

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

2)在Fragment的onAttach中,将活动转换为Interface类型并调用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框架也建议的
Akhil Dad

2

更改标题的最佳活动 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

一个简单的Kotlin示例

假设这些gradle dep在您的项目中匹配或更高版本:

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


    }

1

如果您的主要活动包含很多片段,则通常使用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>

1

将您的答案保存在String []对象中,并将其在MainActivity中设置为OnTabChange()如下所示

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

这样的铸造方式的缺点

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

是您的片段在MainActivityFragment之外不再可重用。如果您不打算在该活动之外使用它,那么就没有问题。更好的方法是根据活动有条件地设置标题。因此,在您的片段中,您应该写:

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

1

如果您使用的是由Google提供的android studio 1.4稳定模板,而不是简单的模板,则必须在onNavigationItemSelectedmethode中编写以下代码,其中相关条件的片段调用if条件。

 setTitle("YOUR FRAGMENT TITLE");

如果您可以直接从活动中访问标题,那就太好了……但是,如果标题是片段中的动态设置字符串,则片段和活动之间需要进行通信
me_

1

我得到了一个非常简单的解决方案,可以在片段或任何活动中设置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");

优秀!如果使用Android导航组件,则使用toolbar_title会覆盖片段标题。
Paixols '18

0

只是要添加到所选答案中,您可能还想在主要活动中添加第二种方法。因此,您最终将在主要活动中使用以下方法:

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

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

这将允许您从String变量以及资源ID(例如R.id.this_is_a_string从strings.xml文件)设置标题。getSupportActionBar().setTitle()由于它允许您传递资源ID,因此它的工作方式也更像工作原理。


0

如上所述,有很多方法。您也可以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);
    }
}

0

至少对我来说,在运行时更改选项卡标题有一个简单的答案(经过反复研究):

TabLayout tabLayout =(TabLayout)findViewById(R.id.tabs); tabLayout.getTabAt(MyTabPos).setText(“ My New Text”);


0

如果您正在使用ViewPager(例如我的情况),则可以使用:

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

onPageSelected你的方法VIEW_PAGER.addOnPageChangeListener


0

在您的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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.