【Android】android.app.Fragment实现选
作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc。
书客创作
前言:
Fragment是Android3.0后引入的一个新的API,它出现的初衷是为了适应大屏幕的平板电脑, 当然现在它仍然是平板APP UI设计的宠儿,而且我们普通手机开发也会加入这个Fragment, 我们可以把它看成一个小型的Activity,又称Activity片段!想想,如果一个很大的界面,我们就一个布局,写起界面来会有多麻烦,而且如果组件多的话是管理起来也很麻烦!而使用Fragment我们可以把屏幕划分成几块,然后进行分组,进行一个模块化的管理!从而可以更加方便的在运行过程中动态地更新Activity的用户界面!另外Fragment并不能单独使用,它需要嵌套在Activity中使用,尽管它拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响,比如Activity被destory销毁了,它也会跟着销毁!
Fragment简介
Fragment生命周期图上图是Fragment的生命周期图,从该图中可以看到Fragment拥有跟Activity相似的生命周期,例如都有onCreate,onStart,onStop等过程。当然它也有自己独特的过程例如onCreateView,onActivityCreated等。官方文档说创建Fragment时至少需要实现三个方法:onCreate,onCreateView,OnPause。实际上真正需要重写的方法只有onCreateView一个,因为该方法是给Fragment提供视图的,所以重写该方法必不可少。
Fragment该如何使用?
本小节就android.app.Fragment实现选项卡功能来说明Fragment的一些用法。
基本思想:android.app.Fragment只能结合Activity使用,在使用上其实可以把它当成Activity中的一个视图控件。说的简单一点就是在一个Activity中需要几个布局界面,就添加几个Fragment来呈现和管理。例如:要实现一个带有三个选项的选项卡:
一、布局
首先是Activity的布局,Activity需要显示选项卡界面和内容界面两个部分,这里的内容区由FrameLayout进行包裹,具体呈现内容交由Fragment来实现:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
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="#F5F5F5" >
<RelativeLayout
android:id="@+id/main_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/main_image"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_gravity="center_horizontal"
android:contentDescription="@string/desc"
android:src="@drawable/main_tab1" />
<TextView
android:id="@+id/main_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/main"
android:textColor="#929598"
android:textSize="15sp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/navigation_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/navigation_image"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_gravity="center_horizontal"
android:contentDescription="@string/desc"
android:src="@drawable/navigation_tab2" />
<TextView
android:id="@+id/navigation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/navigation"
android:textColor="#929598"
android:textSize="15sp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_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/more_image"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/more_tab2" />
<TextView
android:id="@+id/more_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/more"
android:textColor="#929598"
android:textSize="15sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
二、Fragment加载布局文件
在Activity的布局文件中,内容区是由FrameLayout进行包裹,具体呈现内容布局是由Fragment来实现,那么Fragment是如何实现一个界面布局呢?假如这里有一个布局文件fragment_main.xml,那么实现该布局文件代码如下:
public class Main extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View contactsLayout = inflater.inflate(R.layout.fragment_main, container, false);
return contactsLayout;
}
}
从上面可以看出页面不是一个Activity,而是一个Fragment。实现布局的加载是通过onCreateView()这个方法、通过LayoutInflater来获取页面view、false指的是添加非子视图、如果是true的话,就是添加子视图的意思。
三、最后,Fragment实现选项切换
在说明Fragment实现选项切换之前,首先要知道与FragmentTransaction相关的几个重要的方法。
// Fragment管理类
FragmentManager fragmentManager = getFragmentManager();
// 开启一个Fragment事务
FragmentTransaction transaction = fragmentManager.beginTransaction();
FragmentTransaction是Fragment的事务类,也是最直接操作Fragment的类。
transaction.add(int containerViewId, Fragment fragment);
add是用来添加一个Fragment到事务当中。
transaction.show(Fragment fragment);
show方法是用来展示Fragment。
transaction.commit();
提交Fragment事务。
transaction.hide(Fragment fragment);
hide方法是隐藏Fragment,与show方法相对。
下面看一下Activity具体怎么实现页面的跳转:
public class MainActivity extends Activity implements OnClickListener {
/**
* 用于展示主页的Fragment
*/
private Main mainFragment;
/**
* 用于展示导航的Fragment
*/
private Navigation navigationFragment;
/**
* 用于展示更多的Fragment
*/
private More moreFragment;
/**
* 主页界面布局
*/
private View mainLayout;
/**
* 导航界面布局
*/
private View navigationLayout;
/**
* 更多界面布局
*/
private View moreLayout;
/**
* 在Tab布局上显示主页图标的控件
*/
private ImageView mainImage;
/**
* 在Tab布局上显示导航图标的控件
*/
private ImageView navigationImage;
/**
* 在Tab布局上显示更多图标的控件
*/
private ImageView moreImage;
/**
* 在Tab布局上显示主页标题的控件
*/
private TextView mainText;
/**
* 在Tab布局上显示导航标题的控件
*/
private TextView navigationText;
/**
* 在Tab布局上显示更多标题的控件
*/
private TextView moreText;
/**
* 用于对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() {
mainLayout = findViewById(R.id.main_layout);
navigationLayout = findViewById(R.id.navigation_layout);
moreLayout = findViewById(R.id.more_layout);
mainImage = (ImageView) findViewById(R.id.main_image);
navigationImage = (ImageView) findViewById(R.id.navigation_image);
moreImage = (ImageView) findViewById(R.id.more_image);
mainText = (TextView) findViewById(R.id.main_text);
navigationText = (TextView) findViewById(R.id.navigation_text);
moreText = (TextView) findViewById(R.id.more_text);
mainLayout.setOnClickListener(this);
navigationLayout.setOnClickListener(this);
moreLayout.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_layout:
// 当点击了主页tab时,选中第1个tab
setTabSelection(0);
break;
case R.id.navigation_layout:
// 当点击了导航tab时,选中第2个tab
setTabSelection(1);
break;
case R.id.more_layout:
// 当点击了更多tab时,选中第3个tab
setTabSelection(2);
break;
default:
break;
}
}
/**
* 根据传入的index参数来设置选中的tab页。
*
* @param index 每个tab页对应的下标。0表示主页,1表示导航,2表示更多
*/
private void setTabSelection(int index) {
// 每次选中之前先清楚掉上次的选中状态
clearSelection();
// 开启一个Fragment事务
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况
hideFragments(transaction);
switch (index) {
case 0:
// 当点击了主页tab时,改变控件的图片和文字颜色
mainImage.setImageResource(R.drawable.main_tab1);
mainText.setTextColor(Color.parseColor("#0079FF"));
if (mainFragment == null) {
// 如果MessageFragment为空,则创建一个并添加到界面上
mainFragment = new Main();
transaction.add(R.id.content, mainFragment);
} else {
// 如果mainFragment不为空,则直接将它显示出来
transaction.show(mainFragment);
}
break;
case 1:
// 当点击了导航tab时,改变控件的图片和文字颜色
navigationImage.setImageResource(R.drawable.navigation_tab1);
navigationText.setTextColor(Color.BLUE);
if (navigationFragment == null) {
// 如果navigationFragment为空,则创建一个并添加到界面上
navigationFragment = new Navigation();
transaction.add(R.id.content, navigationFragment);
} else {
// 如果navigationFragment不为空,则直接将它显示出来
transaction.show(navigationFragment);
}
break;
case 2:
// 当点击了更多tab时,改变控件的图片和文字颜色
moreImage.setImageResource(R.drawable.more_tab1);
moreText.setTextColor(Color.BLUE);
if (moreFragment == null) {
// 如果moreFragment为空,则创建一个并添加到界面上
moreFragment = new More();
transaction.add(R.id.content, moreFragment);
} else {
// 如果moreFragment不为空,则直接将它显示出来
transaction.show(moreFragment);
}
break;
}
transaction.commit();
}
/**
* 清除掉所有的选中状态。
*/
private void clearSelection() {
mainImage.setImageResource(R.drawable.main_tab2);
mainText.setTextColor(Color.parseColor("#929598"));
navigationImage.setImageResource(R.drawable.navigation_tab2);
navigationText.setTextColor(Color.parseColor("#929598"));
moreImage.setImageResource(R.drawable.more_tab2);
moreText.setTextColor(Color.parseColor("#929598"));
}
/**
* 将所有的Fragment都置为隐藏状态。
*
* @param transaction 用于对Fragment执行操作的事务
*/
private void hideFragments(FragmentTransaction transaction) {
if (mainFragment != null) {
transaction.hide(mainFragment);
}
if (navigationFragment != null) {
transaction.hide(navigationFragment);
}
if (moreFragment != null) {
transaction.hide(moreFragment);
}
}
}
在本案例中一共提供了三个Fragment,分别是Main(mainFragment)、Navigation(navigationFragment)、More(moreFragment),这三个Fragment是虚构对象,具体代码未给出,这里只是用来说Activity内如何操作Fragment。实际上通过以上代码可以看出Fragment实现选项切换是通过FragmentTransaction来实现的,即由核心方法setTabSelection来实现。
微信公众号:书客创作