现在Fragment的应用真的是越来越广泛了,之前Android在3.0版本加入Fragment的时候,主要是为了解决Android Pad屏幕比较大,空间不能充分利用的问题,但现在即使只是在手机上,也有很多的场景可以运用到Fragment了,今天我们就来学习其中一个特别棒的应用技巧。很多手机应用都会有一个非常类似的功能,即屏幕的下方显示一行Tab标签选项,点击不同的标签就可以切换到不同的界面,如以下几个应用所示:

       

直接上实例:

新建一个项目,起名就叫FragmentDemo,这里我使用的是4.0的API。

下面开始编程工作,这里我们首先需要去编写一个类似于QQ的主界面,当然只会去编写界面最下方的TabHost部分,而不会编写上面的内容界面部分,因为内容界面是应该写在Fragment的布局里的。

打开或新建activity_main.xml作为程序的主布局文件,在里面加入如下代码:

  1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical" >
5
6 <FrameLayout
7 android:id="@+id/content"
8 android:layout_width="match_parent"
9 android:layout_height="0dp"
10 android:layout_weight="1" >
11 </FrameLayout>
12
13 <LinearLayout
14 android:layout_width="match_parent"
15 android:layout_height="60dp"
16 android:background="@drawable/tab_bg" >
17
18 <RelativeLayout
19 android:id="@+id/message_layout"
20 android:layout_width="0dp"
21 android:layout_height="match_parent"
22 android:layout_weight="1" >
23
24 <LinearLayout
25 android:layout_width="match_parent"
26 android:layout_height="wrap_content"
27 android:layout_centerVertical="true"
28 android:orientation="vertical" >
29
30 <ImageView
31 android:id="@+id/message_image"
32 android:layout_width="wrap_content"
33 android:layout_height="wrap_content"
34 android:layout_gravity="center_horizontal"
35 android:src="@drawable/message_unselected" />
36
37 <TextView
38 android:id="@+id/message_text"
39 android:layout_width="wrap_content"
40 android:layout_height="wrap_content"
41 android:layout_gravity="center_horizontal"
42 android:text="消息"
43 android:textColor="#82858b" />
44 </LinearLayout>
45 </RelativeLayout>
46
47 <RelativeLayout
48 android:id="@+id/contacts_layout"
49 android:layout_width="0dp"
50 android:layout_height="match_parent"
51 android:layout_weight="1" >
52
53 <LinearLayout
54 android:layout_width="match_parent"
55 android:layout_height="wrap_content"
56 android:layout_centerVertical="true"
57 android:orientation="vertical" >
58
59 <ImageView
60 android:id="@+id/contacts_image"
61 android:layout_width="wrap_content"
62 android:layout_height="wrap_content"
63 android:layout_gravity="center_horizontal"
64 android:src="@drawable/contacts_unselected" />
65
66 <TextView
67 android:id="@+id/contacts_text"
68 android:layout_width="wrap_content"
69 android:layout_height="wrap_content"
70 android:layout_gravity="center_horizontal"
71 android:text="联系人"
72 android:textColor="#82858b" />
73 </LinearLayout>
74 </RelativeLayout>
75
76 <RelativeLayout
77 android:id="@+id/news_layout"
78 android:layout_width="0dp"
79 android:layout_height="match_parent"
80 android:layout_weight="1" >
81
82 <LinearLayout
83 android:layout_width="match_parent"
84 android:layout_height="wrap_content"
85 android:layout_centerVertical="true"
86 android:orientation="vertical" >
87
88 <ImageView
89 android:id="@+id/news_image"
90 android:layout_width="wrap_content"
91 android:layout_height="wrap_content"
92 android:layout_gravity="center_horizontal"
93 android:src="@drawable/news_unselected" />
94
95 <TextView
96 android:id="@+id/news_text"
97 android:layout_width="wrap_content"
98 android:layout_height="wrap_content"
99 android:layout_gravity="center_horizontal"
100 android:text="动态"
101 android:textColor="#82858b" />
102 </LinearLayout>
103 </RelativeLayout>
104
105 <RelativeLayout
106 android:id="@+id/setting_layout"
107 android:layout_width="0dp"
108 android:layout_height="match_parent"
109 android:layout_weight="1" >
110
111 <LinearLayout
112 android:layout_width="match_parent"
113 android:layout_height="wrap_content"
114 android:layout_centerVertical="true"
115 android:orientation="vertical" >
116
117 <ImageView
118 android:id="@+id/setting_image"
119 android:layout_width="wrap_content"
120 android:layout_height="wrap_content"
121 android:layout_gravity="center_horizontal"
122 android:src="@drawable/setting_unselected" />
123
124 <TextView
125 android:id="@+id/setting_text"
126 android:layout_width="wrap_content"
127 android:layout_height="wrap_content"
128 android:layout_gravity="center_horizontal"
129 android:text="设置"
130 android:textColor="#82858b" />
131 </LinearLayout>
132 </RelativeLayout>
133 </LinearLayout>
134
135 </LinearLayout>

这段布局代码虽然有点长,但其实主要就分为两部分。第一个部分就是FrameLayout,这里只是给FrameLayout的id设置成content,并没有在里面添加任何具体的内容,因为具体的内容是要在后面动态进行添加的。第二个部分就是FrameLayout下面的LinearLayout,这个LinearLayout中包含的就是整个类似于TabHost的布局。可以看到,我们将这个LinearLayout又等分成了四份,每一份中都会显示一个ImageView和一个TextView。ImageView用于显示当前Tab的图标,TextView用于显示当前Tab的标题,这个效果就会和QQ非常得类似。

既然是等分成了四分,那接下来我们自然要去分别实现四个Fragment和它们的布局了。

新建一个message_layout.xml作为消息界面的布局,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <LinearLayout
7 android:layout_width="wrap_content"
8 android:layout_height="wrap_content"
9 android:layout_centerInParent="true"
10 android:orientation="vertical" >
11
12 <ImageView
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:layout_gravity="center_horizontal"
16 android:src="@drawable/message_selected" />
17
18 <TextView
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_gravity="center_horizontal"
22 android:padding="10dp"
23 android:text="这是消息界面"
24 android:textSize="20sp" />
25 </LinearLayout>
26
27 </RelativeLayout>

然后要去创建对应这个布局的Fragment。新建MessageFragment继承自Fragment,代码如下所示:

1     public class MessageFragment extends Fragment {
2 public View onCreateView(LayoutInflater inflater, ViewGroup container,
3 Bundle savedInstanceState) {
4 View messageLayout = inflater.inflate(R.layout.message_layout,
5 container, false);
6 return messageLayout;
7 }
8 }

后面就是依葫芦画瓢,把其它几个Fragment以及对应的布局创建出来。

新建contacts_layout.xml作为联系人界面的布局,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <LinearLayout
7 android:layout_width="wrap_content"
8 android:layout_height="wrap_content"
9 android:layout_centerInParent="true"
10 android:orientation="vertical" >
11
12 <ImageView
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:layout_gravity="center_horizontal"
16 android:src="@drawable/contacts_selected" />
17
18 <TextView
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_gravity="center_horizontal"
22 android:padding="10dp"
23 android:text="这是联系人界面"
24 android:textSize="20sp" />
25 </LinearLayout>
26
27 </RelativeLayout>

再新建ContactsFragment继承自Fragment,代码如下所示:

1     public class ContactsFragment extends Fragment {
2 @Override
3 public View onCreateView(LayoutInflater inflater, ViewGroup container,
4 Bundle savedInstanceState) {
5 View contactsLayout = inflater.inflate(R.layout.contacts_layout,
6 container, false);
7 return contactsLayout;
8 }
9 }

然后新建news_layout.xml作为动态界面的布局,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <LinearLayout
7 android:layout_width="wrap_content"
8 android:layout_height="wrap_content"
9 android:layout_centerInParent="true"
10 android:orientation="vertical" >
11
12 <ImageView
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:layout_gravity="center_horizontal"
16 android:src="@drawable/news_selected" />
17
18 <TextView
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_gravity="center_horizontal"
22 android:padding="10dp"
23 android:text="这是动态界面"
24 android:textSize="20sp" />
25 </LinearLayout>
26
27 </RelativeLayout>

再新建NewsFragment继承自Fragment,代码如下所示:

1     public class NewsFragment extends Fragment {
2 @Override
3 public View onCreateView(LayoutInflater inflater, ViewGroup container,
4 Bundle savedInstanceState) {
5 View newsLayout = inflater.inflate(R.layout.news_layout, container,
6 false);
7 return newsLayout;
8 }
9 }

最后新建setting_layout.xml作为设置界面的布局,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent" >
5
6 <LinearLayout
7 android:layout_width="wrap_content"
8 android:layout_height="wrap_content"
9 android:layout_centerInParent="true"
10 android:orientation="vertical" >
11
12 <ImageView
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:layout_gravity="center_horizontal"
16 android:src="@drawable/setting_selected" />
17
18 <TextView
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_gravity="center_horizontal"
22 android:padding="10dp"
23 android:text="这是设置界面"
24 android:textSize="20sp" />
25 </LinearLayout>
26
27 </RelativeLayout>

再新建SettingFragment继承自Fragment,代码如下所示:

1 public class SettingFragment extends Fragment {
2 @Override
3 public View onCreateView(LayoutInflater inflater, ViewGroup container,
4 Bundle savedInstanceState) {
5 View settingLayout = inflater.inflate(R.layout.setting_layout,
6 container, false);
7 return settingLayout;
8 }
9 }

这样我们就把每一个Fragment,以及它们所对应的布局文件都创建好了。接下来也就是最关键的步骤了,打开或新建MainActivity作为主Activity,代码如下所示:

 /** * 项目的主Activity,所有的Fragment都嵌入在这里。 * * @author guolin */
public class MainActivity extends Activity implements OnClickListener {
/** * 用于展示消息的Fragment */
private MessageFragment messageFragment;
/** * 用于展示联系人的Fragment */
private ContactsFragment contactsFragment;
/** * 用于展示动态的Fragment */
private NewsFragment newsFragment;
/** * 用于展示设置的Fragment */
private SettingFragment settingFragment;
/** * 消息界面布局 */
private View messageLayout;
/** * 联系人界面布局 */
private View contactsLayout;
/** * 动态界面布局 */
private View newsLayout;
/** * 设置界面布局 */
private View settingLayout;
/** * 在Tab布局上显示消息图标的控件 */
private ImageView messageImage;
/** * 在Tab布局上显示联系人图标的控件 */
private ImageView contactsImage;
/** * 在Tab布局上显示动态图标的控件 */
private ImageView newsImage;
/**
* 在Tab布局上显示设置图标的控件
*/
private ImageView settingImage;
/** * 在Tab布局上显示消息标题的控件 */
private TextView messageText;
/** * 在Tab布局上显示联系人标题的控件 */
private TextView contactsText;
/** * 在Tab布局上显示动态标题的控件 */
private TextView newsText;
/** * 在Tab布局上显示设置标题的控件 */
private TextView settingText;
/** * 用于对Fragment进行管理 */
private FragmentManager fragmentManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
// 初始化布局元素
initViews();
fragmentManager = getFragmentManager();
// 第一次启动时选中第0个tab
setTabSelection(0);
} /** * 在这里获取到每个需要用到的控件的实例,并给它们设置好必要的点击事件。 */
private void initViews() {
messageLayout = findViewById(R.id.message_layout);
contactsLayout = findViewById(R.id.contacts_layout);
newsLayout = findViewById(R.id.news_layout);
settingLayout = findViewById(R.id.setting_layout);
messageImage = (ImageView) findViewById(R.id.message_image);
contactsImage = (ImageView) findViewById(R.id.contacts_image);
newsImage = (ImageView) findViewById(R.id.news_image);
settingImage = (ImageView) findViewById(R.id.setting_image);
messageText = (TextView) findViewById(R.id.message_text);
contactsText = (TextView) findViewById(R.id.contacts_text);
newsText = (TextView) findViewById(R.id.news_text);
settingText = (TextView) findViewById(R.id.setting_text);
messageLayout.setOnClickListener(this);
contactsLayout.setOnClickListener(this);
newsLayout.setOnClickListener(this);
settingLayout.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.message_layout:
setTabSelection(0);
break;
case R.id.contacts_layout:
setTabSelection(1);
break;
case R.id.news_layout:
setTabSelection(2);
break;
case R.id.setting_layout:
setTabSelection(3);
break;
default: break;
}
}
/** * 根据传入的index参数来设置选中的tab页。 * * @param index *
每个tab页对应的下标。0表示消息,1表示联系人,2表示动态,3表示设置。 */
private void setTabSelection(int index) {
// 每次选中之前先清楚掉上次的选中状态
clearSelection();
// 开启一个Fragment事务 FragmentTransaction
transaction = fragmentManager.beginTransaction();
//先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况
hideFragments(transaction);
switch (index) {
case 0: //当点击了消息tab时,改变控件的图片和文字颜色
messageImage.setImageResource(R.drawable.message_selected);
messageText.setTextColor(Color.WHITE);
if (messageFragment ==null) {
// 如果MessageFragment为空,则创建一个并添加到界面上
messageFragment = new MessageFragment();
transaction.add(R.id.content, messageFragment);
} else {
// 如果MessageFragment不为空,则直接将它显示出来
transaction.show(messageFragment);
}
break;
case 1: // 当点击了联系人tab时,改变控件的图片和文字颜色
contactsImage.setImageResource(R.drawable.contacts_selected);
contactsText.setTextColor(Color.WHITE);
if (contactsFragment ==null) {
// 如果ContactsFragment为空,则创建一个并添加到界面上
contactsFragment = new ContactsFragment();
transaction.add(R.id.content, contactsFragment);
} else {
// 如果ContactsFragment不为空,则直接将它显示出来
transaction.show(contactsFragment); }
break;
case 2: //当点击了动态tab时,改变控件的图片和文字颜色
newsImage.setImageResource(R.drawable.news_selected);
newsText.setTextColor(Color.WHITE);
if (newsFragment == null) {
// 如果NewsFragment为空,则创建一个并添加到界面上
newsFragment = new NewsFragment(); transaction.add(R.id.content, newsFragment); }
else {
// 如果NewsFragment不为空,则直接将它显示出来
transaction.show(newsFragment);
}
break;
case 3:
default:
//当点击了设置tab时,改变控件的图片和文字颜色
settingImage.setImageResource(R.drawable.setting_selected);
settingText.setTextColor(Color.WHITE);
if (settingFragment ==null) {
// 如果SettingFragment为空,则创建一个并添加到界面上
settingFragment = new SettingFragment();
transaction.add(R.id.content,settingFragment); }
else { // 如果SettingFragment不为空,则直接将它显示出来
transaction.show(settingFragment);
}
break;
}
transaction.commit();
}
/** * 清除掉所有的选中状态。 */
private void clearSelection() {
messageImage.setImageResource(R.drawable.message_unselected);
messageText.setTextColor(Color.parseColor("#82858b"));
contactsImage.setImageResource(R.drawable.contacts_unselected);
contactsText.setTextColor(Color.parseColor("#82858b"));
newsImage.setImageResource(R.drawable.news_unselected);
newsText.setTextColor(Color.parseColor("#82858b"));
settingImage.setImageResource(R.drawable.setting_unselected);
settingText.setTextColor(Color.parseColor("#82858b")); } /** *
将所有的Fragment都置为隐藏状态。 * * @param transaction * 用于对Fragment执行操作的事务
*/ private void hideFragments(FragmentTransaction transaction) {
if (messageFragment != null) {
transaction.hide(messageFragment);
} if (contactsFragment != null) {
transaction.hide(contactsFragment);
}
if (newsFragment != null) {
transaction.hide(newsFragment);
}
if (settingFragment != null) {
transaction.hide(settingFragment);
}
}
}

这个类中的注释已经写得非常详细了,下面我再带大家简单梳理一遍。在onCreate()方法中先是调用了initViews()来获取每个控件的实例,并给相应的控件设置好点击事件,然后调用setTabSelection()方法设置默认的选中项,这里传入的0说明默认选中第1个Tab项。那么setTabSelection()方法中又是如何处理的呢?可以看到,首先第一步是调用clearSelection()方法来清理掉之前的选中状态,然后开启一个Fragment事务,并隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上。接下来根据传入的index参数判断出选中的是哪一个Tab项,并改变该Tab项的图标和文字颜色,然后将相应的Fragment添加到界面上。这里注意一个细节,我们添加Fragment的时候并没有使用replace()方法,而是会先判断一下该Fragment是否为空,如果是空的则调用add()方法添加一个进来,如果不是空的则直接调用show()方法显示出来即可。那么为什么没有使用replace()方法呢?这是因为replace()方法会将被替换掉的那个Fragment彻底地移除掉,该Fragment的生命周期就结束了。当再次点击刚才那个Tab项的时候,就会让该Fragment的生命周期重新开始,onCreate()、onCreateView()等方法都会重新执行一遍。这显然不是我们想要的,也和ActivityGroup的工作原理不符,因此最好的解决方案就是使用hide()和show()方法来隐藏和显示Fragment,这就不会让Fragment的生命周期重走一遍了。

设置完默认选中项后,我们当然还可以通过点击Tab项来自由地切换界面,这就会进入到onClick()方法中。onClick()方法中的逻辑判断非常简单,当点击了消息标签时就会选中第1个tab项,点击联系人标签时就会选中第2个tab项,点击动态标签时就会选中第3个tab项,点击设置标签时就会选中第4个tab项。都是通过调用setTabSelection()方法来完成的,只是传入了不同的参数。

好了,这样我们就将全部的代码都编写完成了,下面就来运行一下吧

原文来自:雨枫技术教程网 http://www.fengfly.com

原文网址:http://www.fengfly.com/plus/view-215109-3.html

Android使用Fragment实现TabHost效果的更多相关文章

  1. ViewPager+Fragment替代TabHost效果的简单示例

    本示例旨在展示fragment替代tabhost的效果,具体的业务逻辑还要根据这个示例进行扩展. 效果图如下: 主Activity代码: package com.llb.view; import ja ...

  2. Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信

    以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html 我前两天写过一篇博客<Android使用Fragment来 ...

  3. Android 自学之选项卡TabHost

    选项卡(TabHost)是一种非常实用的组件,TabHost可以很方便地在窗口上放置多个标签页,每个标签页相当于获得了一个与外部容器相同大小的组建摆放区域.通过这种方式,就可以在一个容器中放置更多组件 ...

  4. Android实现网易新闻客户端效果

    下面来简单实现一下网易新闻客户端左右切换的效果,当然实际项目上肯定不能这样写,还有很多需要优化的地方. activity_main.xml [html] view plaincopyprint? &l ...

  5. Android中Fragment和ViewPager那点事儿(仿微信APP)

    在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...

  6. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  7. Android - ViewPager+Fragment初始化问题

    Android应用开发中,经常会用到ViewPager + Fragment,虽然效果不错,但随之而来的还有一些问题,下面就说说其中的初始化问题. ViewPager初始化时会预加载前后的2个页面,即 ...

  8. 33.Android之Fragment学习

    Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...

  9. Android之Fragment(二)

    本文主要内容 如何管理Fragment回退栈 Fragment如何与Activity交互 Fragment与Activity交互的最佳实践 没有视图的Fragment的用处 使用Fragment创建对 ...

随机推荐

  1. 转载: ASP.NET Core入门系列文章

    今天在网上发现了ithome上的asp.net core 系列文章,对于新手入门还不错,这里转载一下,也方便查阅. [Day01] 從頭開始 [Day02] 程式生命週期 (Application L ...

  2. Linux--信号阻塞与屏蔽

    1. sigprocmask函数提供屏蔽和解除屏蔽信号的功能. 从而实现关键代码的运行不被打断. 函数声明如下: int sigprocmask(int how, const sigset_t *se ...

  3. [Asp.net core]bootstrap分页

    摘要 一直在用前后端分离,在一个后台管理的页面中,尝试封装了一个辅助类. 类 /// <summary> /// 分页viewmodel /// </summary> /// ...

  4. aglio报错解决

    Cannot write or read cache for themes (ENOENT on cache folder) aglio -i ./api.md -o api.html >> ...

  5. SSE图像算法优化系列四:图像转置的SSE优化(支持8位、24位、32位),提速4-6倍

    一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...

  6. grid - 网格项目跨行或跨列

    默认情况下网格项目跨度只有一个列和行,但可以跨越多个行和列. 1.可以通过设置grid-column-end和grid-column-start距离多个网络线号实现多个列跨越. <view cl ...

  7. CSS 居中布局

    来源:http://www.cnblogs.com/QianBoy/p/8539077.html 水平居中 1)使用inline-block+text-align 原理:先将子框由块级元素改变为行内块 ...

  8. 编写SHELL脚本--判断用户的参数

    测试语句格式: [ 条件表达式 ] 常见的几种形式: [ -d /etc ]  判断/etc是不是一个目录类型, [ -e /etc/php.ini ] 判断/etc/php.ini 文件是否存在 [ ...

  9. 如何部署hadoop集群

    假设我们有三台服务器,他们的角色我们做如下划分: 10.96.21.120 master 10.96.21.119 slave1 10.96.21.121 slave2 接下来我们按照这个配置来部署h ...

  10. 【SqlServer】SqlServer的游标使用

    什么是游标 结果集,结果集就是select查询之后返回的所有行数据的集合. 游标则是处理结果集的一种机制吧,它可以定位到结果集中的某一行,多数据进行读写,也可以移动游标定位到你所需要的行中进行操作数据 ...