使用Fragment实现类似TabHost标签栏的效果
在前几天,我写了篇《Android TabHost的使用》简单的介绍了其使用的方法,但是在实现的时候发现TabHost已经被官方遗弃了。虽然我觉得TabHost还是多好用的(可能因为我这种菜鸟不清楚吧)不知道为什么官方会遗弃,但应该还是有原因的吧。
首先,我们来简单的了解一下Fragment。Fragment是Android在3.0中引入的概念用来在一个Activity中描述一些行为或一部分用户界面,支持不同分辨率屏幕的动态和灵活的UI设计。Fragment必须总是被嵌入到一个Activity中,它们的生命周期直接被其所属的宿主Activity的生命周期所影响。
创建Fragment的方法有两种:
- 在布局文件中声明Fragment。
- 从布局文件中读取并生成Fragemnt(使用onCreate()的方法提供的LayoutInflater对象参数)。
每一个Fragment都需要一个唯一的标识,如果Activity重启,系统可以用这个标识来回复Fragment(也可以用来处理Fragment事务,例如移除它),有三种方法来为一个 Fragment提供一个标识:
- 为android:id属性提供一个唯一的ID。
- 为android:tag属性提供一个唯一字符串。
- 如果以上两个都没有提供,则系统使用容器view的ID。
好了,言归正传,我们还是来了解一下Fragment实现类似TabHost标签栏的效果吧。
(这个例子是同学给我的,不知道是他自己做的还是在网上找的Demo)
我们先来看看,效果图:
首先还是从布局文件开始吧:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:background="@drawable/tab_bg" > <RelativeLayout android:id="@+id/message_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical" > <ImageView android:id="@+id/message_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/message_unselected" /> <TextView android:id="@+id/message_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="消息" android:textColor="#82858b" /> </LinearLayout> </RelativeLayout> <RelativeLayout android:id="@+id/contacts_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical" > <ImageView android:id="@+id/contacts_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/contacts_unselected" /> <TextView android:id="@+id/contacts_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="联系人" android:textColor="#82858b" /> </LinearLayout> </RelativeLayout> <RelativeLayout android:id="@+id/news_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical" > <ImageView android:id="@+id/news_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/news_unselected" /> <TextView android:id="@+id/news_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="动态" android:textColor="#82858b" /> </LinearLayout> </RelativeLayout> <RelativeLayout android:id="@+id/setting_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical" > <ImageView android:id="@+id/setting_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/setting_unselected" /> <TextView android:id="@+id/setting_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="设置" android:textColor="#82858b" /> </LinearLayout> </RelativeLayout> </LinearLayout> </LinearLayout>
contacts_layout.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/contacts_selected" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="10dp" android:text="这是联系人界面" android:textSize="20sp" /> </LinearLayout> </RelativeLayout>
message_layout.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/message_selected" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="10dp" android:text="这是消息界面" android:textSize="20sp" /> </LinearLayout> </RelativeLayout>
news_layout.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/news_selected" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="10dp" android:text="这是动态界面" android:textSize="20sp" /> </LinearLayout> </RelativeLayout>
setting_layout.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/setting_selected" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="10dp" android:text="这是设置界面" android:textSize="20sp" /> </LinearLayout> </RelativeLayout>
然后来实现JAVA代码:
MainActivity.java
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; 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: // 当点击了消息tab时,选中第1个tab setTabSelection(0); break; case R.id.contacts_layout: // 当点击了联系人tab时,选中第2个tab setTabSelection(1); break; case R.id.news_layout: // 当点击了动态tab时,选中第3个tab setTabSelection(2); break; case R.id.setting_layout: // 当点击了设置tab时,选中第4个tab 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); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
ContactsFragment.java
public class ContactsFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View contactsLayout = inflater.inflate(R.layout.contacts_layout, container, false); return contactsLayout; } }
MessageFragment.java
public class MessageFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View messageLayout = inflater.inflate(R.layout.message_layout, container, false); return messageLayout; } }
NewsFragment.java
public class NewsFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View newsLayout = inflater.inflate(R.layout.news_layout, container, false); return newsLayout; } }
SettingFragment.java
public class SettingFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View settingLayout = inflater.inflate(R.layout.setting_layout, container, false); return settingLayout; } }
好了,除了资源文件以外,XML和JAVA文件都已完成。运行即可。
Demo下载:http://pan.baidu.com/s/1xSD9G