带有 Fragments 和 FragmentActivity 的 TabHost
Posted
技术标签:
【中文标题】带有 Fragments 和 FragmentActivity 的 TabHost【英文标题】:TabHost with Fragments and FragmentActivity 【发布时间】:2013-06-18 03:34:28 【问题描述】:我正在开发一个 android 应用程序,我想使用 3 个标签页进行导航,每个标签页都使用 Fragments,但我不知道如何创建结构。
我想单独添加每个片段,因为每个片段都不一样,但我不知道在FragmentActivity中添加它们的位置。
我有这些文件。
tabs_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<TabHost android:id="@android:id/tabhost"
android:layout_
android:layout_>
<LinearLayout
android:orientation="vertical"
android:layout_
android:layout_ >
<TabWidget
android:id="@android:id/tabs"
android:layout_
android:layout_
/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_
android:layout_
>
<FrameLayout
android:id="@+id/tabRateAPet"
android:layout_
android:layout_
/>
<FrameLayout
android:id="@+id/tabViewMyRates"
android:layout_
android:layout_
/>
<FrameLayout
android:id="@+id/tabViewGlobalRates"
android:layout_
android:layout_
/>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout>
TabsMain.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
public class MainTabsActivity extends FragmentActivity
public static final String RATE_A_PET = "Rate a Pet";
public static final String MY_RATES = "My Rates";
public static final String GLOBAL_RATES = "Global Rates";
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.tabs_layout);
Tabs.java
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;
public class Tabs extends Fragment implements OnTabChangeListener
private static final String TAG = "FragmentTabs";
public static final String RATE_A_PET = "Rate a Pet";
public static final String MY_RATES = "My Rates";
public static final String GLOBAL_RATES = "Global Rates";
private View mRoot;
private TabHost mTabHost;
private int mCurrentTab;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
// super.onCreateView(inflater, container, savedInstanceState);
mRoot = inflater.inflate(R.layout.tabs_layout, null);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
private void setupTabs()
mTabHost.setup(); // important!
mTabHost.addTab(newTab(RATE_A_PET, R.string.tabRateAPet, R.id.tabRateAPet));
mTabHost.addTab(newTab(MY_RATES, R.string.tabViewMyRates, R.id.tabViewMyRates));
private TabSpec newTab(String tag, int labelId, int tabContentId)
Log.d(TAG, "buildTab(): tag=" + tag);
View indicator = LayoutInflater.from(getActivity()).inflate(
R.layout.tab,
(ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
((TextView) indicator.findViewById(R.id.text)).setText(labelId);
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(indicator);
tabSpec.setContent(tabContentId);
return tabSpec;
@Override
public void onTabChanged(String tabId)
Log.d(TAG, "onTabChanged(): tabId=" + tabId);
if (RATE_A_PET.equals(tabId))
updateTab(tabId, R.id.tabRateAPet);
mCurrentTab = 0;
return;
if (MY_RATES.equals(tabId))
updateTab(tabId, R.id.tabViewMyRates);
mCurrentTab = 1;
return;
if (GLOBAL_RATES.equals(tabId))
updateTab(tabId, R.id.tabViewGlobalRates);
mCurrentTab = 2;
return;
private void updateTab(String tabId, int placeholder)
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(tabId) == null)
fm.beginTransaction()
.replace(placeholder, new RateMyPetActivity(), tabId)
.commit();
【问题讨论】:
看这个教程,如果你觉得有什么困难可以问我...manishkpr.webheavens.com/android-viewpager-example 也可以参考这个wptrafficanalyzer.in/blog/… 【参考方案1】:我建议为每个选项卡创建一个单独的片段文件。我最近也这样做了,所以我在下面概述了我的代码:
布局文件
activity_main.xml
<android.support.v4.app.FragmentTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_
android:layout_>
<LinearLayout
android:orientation="vertical"
android:layout_
android:layout_>
<TabWidget
android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_
android:layout_
android:layout_weight="0"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_
android:layout_
android:layout_weight="0"/>
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_
android:layout_
android:layout_weight="1"/>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
tab1_view.xml //使用此格式添加您各自的选项卡布局(确保更改字符串变量)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical"
tools:context=".DeviceFragment" >
<TextView
android:layout_
android:layout_
android:text="@string/tab1_fragment_string" />
</LinearLayout>
SRC 文件
MainActivity.java //注意在.addTab
进程中我只使用了文本。您还可以使用需要添加到 hdpi 文件夹的可绘制对象添加图标。在这个例子中我也只创建了三个选项卡。
package com.example.applicationname;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
public class MainActivity extends FragmentActivity
// Fragment TabHost as mTabHost
private FragmentTabHost mTabHost;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Tab1"),
Tab1Fragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Tab2"),
Tab2Fragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("tab3").setIndicator("Tab3"),
Tab3Fragment.class, null);
Tab1Fragment.java //再次复制所需数量的选项卡
package com.example.applicationname;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Tab1Fragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
// Inflate the layout for this fragment
View V = inflater.inflate(R.layout.tab1_view, container, false);
return V;
确保您的 R.java 和 strings.xml 文件设置正确,然后您的选项卡应该启动并运行。
【讨论】:
好的。我去检查一下。谢谢。如果这对我有用,我稍后再告诉你:) 我们可以像ios一样将标签移到底部吗? @KylieModen,很好的教程。我试图通过让我的片段之一包含 EditText 来修改它。但是,一旦我尝试输入 EditText,焦点就会转移回选项卡(突出显示当前选项卡)。有什么建议?谢谢 知道了,需要在tabhost.setup中使用getChildFragmentManager()来处理fragment。 请解释使用 tabcontent 和 realtabcontent 的原因,即两种框架布局。【参考方案2】:TabHost 不保留片段的状态。 那么为什么要使用 TabHost?
所以请改用ViewPager 和TabLayout。
Viewpager 的 Prons 优于 Tabhost:
ViewPager 保留 Fragments 状态。如果切换,Mean Fragment 将不会再次重新创建。 内置滑动功能,为用户提供更流畅的体验。 更少的 CPU 消耗,因为 Tabhost 在切换 Tab 时会一次又一次地重新创建 Fragment/Activity。看看区别:
使用 Tablayout + ViewPager(支持滑动,保留 Fragments 状态
使用 TabHost(不支持滑动,不保留状态)
Tablayout + ViewPager 的小代码
// find views by id
ViewPager viewPager = findViewById(R.id.viewpager);
TabLayout tabLayout = findViewById(R.id.tablayout);
// attach tablayout with viewpager
tabLayout.setupWithViewPager(viewPager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
// add your fragments
adapter.addFrag(new SampleFragment(), "Tab1");
adapter.addFrag(new SampleFragment(), "Tab2");
adapter.addFrag(new SampleFragment(), "Tab3");
// set adapter on viewpager
viewPager.setAdapter(adapter);
XML 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout"
android:layout_
android:layout_ />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_
android:layout_
android:layout_weight="1" />
</LinearLayout>
注意如果您还没有使用AndroidX,您需要在布局中更改以下内容。
将com.google.android.material.tabs.TabLayout
更改为android.support.design.widget.TabLayout
Chagne androidx.viewpager.widget.ViewPager
到 android.support.v4.view.ViewPager
但我强烈建议您迁移到 AndroidX,请参阅 @this answer 了解原因。
这是 common ViewPagerAdapter
适用于所有您在应用中的 Viewpager。
public class ViewPagerAdapter extends FragmentStatePagerAdapter
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager)
super(manager);
@Override
public Fragment getItem(int position)
return mFragmentList.get(position);
@Override
public int getCount()
return mFragmentList.size();
@Override
public CharSequence getPageTitle(int position)
return mFragmentTitleList.get(position);
public void addFrag(Fragment fragment)
mFragmentList.add(fragment);
mFragmentTitleList.add("");
public void addFrag(Fragment fragment, String title)
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
重要的相关链接
Difference between getSupportFragmentManager() and getChildFragmentManager()? getSupportFragmentManager() versus getFragmentManager() in android 3.0+ Difference between FragmentPagerAdapter and FragmentStatePagerAdapter【讨论】:
以上是关于带有 Fragments 和 FragmentActivity 的 TabHost的主要内容,如果未能解决你的问题,请参考以下文章
TabHost with Activities与ActionBar with Fragments
在Android中使用ActivityGroup或Fragments等正确管理导航?
Android Fragment使用 嵌套Fragments (Nested Fragments) 的使用及常见错误