概览(复习时直观):
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;
}
}
(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;
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>
总结:写的可能有些繁杂,防止日后有些细节写错。
加油,坚持。
2018.6.22 白僧笔记
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;
}
}
(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 白僧笔记