您的位置:首页 > 移动开发 > Android开发

Android使用Fragment实现TabHost效果

2015-01-14 10:14 429 查看
现在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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐