Android的FragmentTabHost使用

概览(复习时直观):
1.布局文件,必须按格式。
2.activity中获取FragmentTabHost,设置Tab标签和Fragment。
  mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator(view),
                FragmentStackSupport.CountingFragment.class, null);
3.自定义指示器和fragment。

正文

历史演变:TabHost+Activity————RadioButton————Fragment————FragmentTabHost+Fragment

1.布局文件编写(activity_main):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <!-- 此FragmentLayout为显示内容的fragment-->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/realTabContent"/>
    <!--id为系统提供的@android:id/tabhost-->
    <android.support.v4.app.FragmentTabHost
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/realTabContent"
        android:id="@android:id/tabhost">
        <!--
            id必须为tabcontent,否则报错
            width和heigh必须为0,否则会变为顶部导航栏,布局混乱
         -->
        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:id="@android:id/tabcontent"/>
    </android.support.v4.app.FragmentTabHost>
</android.support.v7.widget.LinearLayoutCompat>


2.代码编写,谷歌官方提供了两种编写方式,具体地址https://developer.android.google.cn/reference/android/support/v4/app/FragmentTabHost,如下所示。
(1)
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;

/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments, using FragmentTabHost.
 */
public class FragmentTabs extends FragmentActivity {
    private FragmentTabHost mTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_tabs);
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    }
}
(2)
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentTabsFragmentSupport extends Fragment {
    private FragmentTabHost mTabHost;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mTabHost = new FragmentTabHost(getActivity());
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);

        return mTabHost;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mTabHost = null;
    }
}



3.自己实现
(1)类的编写。如谷歌方法一,需要些一个类继承FragmentActivity,但AppCompatActivity已经继承了FragmentActivity,所以我们不需要编写额外的类,只需在MainActivity中实现功能即可:
public class MainActivity extends AppCompatActivity {

    protected FragmentTabHost fragmentTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        fragmentTabHost=findViewById(android.R.id.tabhost);     //1获取控件
        fragmentTabHost.setup(this,getSupportFragmentManager(),R.id.realTabContent);  //2初始化参数,并设置容器frafment容器id
        TabHost.TabSpec tabSpec=fragmentTabHost.newTabSpec("home").setIndicator("主页"); 3创建tab标签,并设置指示器
        fragmentTabHost.addTab(tabSpec, HomeFragment.class,null);  //4设置tab标签与所对应的自定义fragment类
    }
}

(2)设置个性化指示器(上面的tab标签指示器未免过于单调)
TabSpec的setIndicator方法为标签添加指示器,共有三个方法:
setIndicator(CharSequence label);  为指示器设置文字
setIndicator(CharSequence label, Drawable icon);   为指示器设置文字和图标,但实际使用过程中,只显示文字,不显示图片。要想显示图片,那么字符串只能为"";
setIndicator(View view); 那么要想自定义只能通过此方法,传入一个view;

扩展:那么就借此简单介绍一下布局加载器的几种获取方法:

在Activity中
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.activity_main, null);

在Fragment中
        View view = inflater.inflate(R.layout.fragment_guide_one, container, false);
        return view;

在Adapter中
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = LayoutInflater.from(convertView.getContext()).inflate(R.layout.activity_main, parent, false);
        return view;
    }

在某些特殊情况下,需要使用LayoutInflater,我们是这样获得它的
        LayoutInflater inflater  =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
4.各部分源码展示如下
(1)MainActivity.java:
public class MainActivity extends AppCompatActivity {

    protected FragmentTabHost fragmentTabHost;
    private LayoutInflater inflater;
    private List<Tab> tabs=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initTab();

    }

    private void initTab() {
        Tab tabHome=new Tab(R.string.home,R.drawable.ic_action_home,HomeFragment.class);
        Tab tabHot=new Tab(R.string.hot,R.drawable.ic_action_hot,HotFragment.class);
        Tab tabCategory=new Tab(R.string.category,R.drawable.ic_action_category,CategoryFragment.class);
        Tab tabCart=new Tab(R.string.cart,R.drawable.ic_action_cart,CartFragment.class);
        Tab tabMine=new Tab(R.string.mine,R.drawable.ic_action_mine,MineFragment.class);
        tabs.add(tabHome);
        tabs.add(tabCategory);
        tabs.add(tabHot);
        tabs.add(tabMine);
        tabs.add(tabCart);

        inflater=LayoutInflater.from(this);
        fragmentTabHost=findViewById(android.R.id.tabhost);
        fragmentTabHost.setup(this,getSupportFragmentManager(),R.id.realTabContent);

        for (Tab tab:tabs) {

            TabHost.TabSpec tabSpec=fragmentTabHost.newTabSpec(getString(tab.getTitle()));
            tabSpec.setIndicator(buildIndicotor(tab));
            fragmentTabHost.addTab(tabSpec, tab.getFragment(),null);
        }

        fragmentTabHost.setCurrentTab(0);

    }

    private View buildIndicotor(Tab tab) {

        View viewTabSpec=inflater.inflate(R.layout.tab_spec,null);
        ImageView imageView=viewTabSpec.findViewById(R.id.spec_image);
        TextView textView=viewTabSpec.findViewById(R.id.spec_text);
        imageView.setBackgroundResource(tab.getIcon());
        textView.setText(tab.getTitle());

        return viewTabSpec;
    }

}
(2)自定义指示器布局文件tab_spec.xml
<?xml version="1.0" encoding="utf-8"?>

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_centerInParent="true">
        <ImageView
            android:id="@+id/spec_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_action_home"/>
        <TextView
            android:id="@+id/spec_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="名称"/>
    </LinearLayout>

(3)用于存放标题、图标、fragment的bean类
public class Tab {

    private int title;
    private int icon;
    private Class fragment;

    public Tab(int title, int icon, Class fragment) {
        this.title = title;
        this.icon = icon;
        this.fragment = fragment;
    }

    public int getTitle() {
        return title;
    }

    public void setTitle(int title) {
        this.title = title;
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public Class getFragment() {
        return fragment;
    }

    public void setFragment(Class fragment) {
        this.fragment = fragment;
    }

}
(4)fragment,这里只展示一个。
public class HomeFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragment_home,null);
        //注意,root处一定要填null,不然报状态不合法异常
        //异常为:java.lang.IllegalStateException The specified child already has a parent. You must call removeView() on the child's parent first.  
        return view;
    }
}
(5)fragment对应的布局文件R.layout.fragment_home
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="home"/>
</android.support.constraint.ConstraintLayout>


5.基本功能已经实现了,下面添加一下select选择器
drawable目录下新建select_icon_home.xml,初始化标签时,Tab类的构造方法传入该选择器。准备了两张图片,一张为红色,一张为灰色
内容如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/ic_action_home_press"/>    被选中时显示。
    <item android:drawable="@drawable/ic_action_home" />   默认显示。
</selector>
res下新建color类型文件夹,名字为color,在文件夹下创建select_tab_text.xml文件,内容如下:
默认黑色,选中时为红色。在tab_spec的TextView标签中使用,为其添加android:textColor="@color/select_tab_text"。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:color="@android:color/holo_red_dark"/>
    <item android:state_selected="false" android:color="@android:color/black"/>
</selector>


总结:写的可能有些繁杂,防止日后有些细节写错。
加油,坚持。
视频教程资源:菜鸟窝的《菜鸟商城》项目(地址:https://www.cniao5.com/course/10073),如有需求联系weixin:wjx13721


2018.6.22 白僧笔记

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值