fragment的产生和应用场景
产生
Activity展示界面的局限性:
- 界面中的View较多较复杂时候,操作麻烦;
- 手机和平板中,展示效果不一致(平板很大,根据手机设计的界面可能会遇到界面被过分拉长,间隙过大等问题)。
为解决这个问题,可以将Activity按照实现的模块拆分成多个小的模块、容器,这些小的模块或者说小的容器就是fragment,fragment有自己UI和独立的生命周期。每个模块设置好,拼接成Activity的界面,就会优化很多。界面会根据设备动态调整。
应用场景
大体上可以分为两类使用场景
1.同一个Activity设置多个fragment界面(比如上图这个列表+内容,点击列表中不同的项就会切出不同的界面)
2.多个Activity中使用同一个fragment,实现界面的复用。
fragment使用
fragment不能被单独使用,必须要嵌入到Activity中,有两种使用方式——静态和动态。
静态使用——通过xml文件引入到Activity
步骤:
- 1.创建一个类继承
Fragment
(app包和v4包下都有,v4包是兼容低版本的)- 2.为fragment编写xml布局视图
- 3.重写Fragment的
onCreateView()
方法
这个方法在fragment第一次创建时,绘制fragment视图时候回调的方法。需要我们定义好fragment的视图,并且以View
的形式返回。- 4.将fragment引用到需要的Activity中。
在Activity的xml布局中使用fragment
标签引入,最重要的是指定android:name
属性,传入的是完整的fragment类的路径。
我们这里以一个标题栏fragment+内容fragment作为一个简单的示例。
1.创建类继承,并重写onCreateView
一个标题fragment和一个内容fragment
public class TitleFragment extends Fragment {
/**
*
* @param inflater 表示布局填充器/加载器,将xml文件转换成view对象
* @param container fragment的界面是要加入到activity中的,这个参数就是fragment要插入activity的
* 布局视图对象
* @param savedInstanceState 和Activity那个参数一个意思,表示存储上一个fragment的信息
* @return View类型,表示当前加载fragment视图,如果fragment不提供视图可以返回null
*/
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_title,null);
RelativeLayout layout = (RelativeLayout)view.findViewById(R.id.rl_layout);
layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getActivity(),"this is title",Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
public class ContentFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_content,null);
}
}
2.fragment的布局
标题
<RelativeLayout
android:id="@+id/rl_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="50dp">
<ImageView
android:id="@+id/iv_back"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:paddingLeft="15dp"
android:src="@drawable/ic_launcher_background"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="777"
android:textColor="#000000"
android:textSize="20sp"/>
</RelativeLayout>
内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textStyle="bold"
android:textSize="20sp"
android:gravity="center"
android:text="888"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3.在Activity的布局中引入fragment标签
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:name="com.example.fragmentplay.fragment.TitleFragment"/>
<fragment
android:id="@+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.fragmentplay.fragment.ContentFragment"/>
</LinearLayout>
动态使用——通过动态逻辑代码动态添加和移除
除了上面的引入,我们有时候需要动态进行切换、删除不同的fragment,这就是个例子:
如果使用静态去引入fragment,显然就不符合需求了。
动态使用fragment,通过逻辑代码而非xml引入。
步骤
- 1.创建Fragment实例(当然前面的继承Fragment,重写方法,和布置xml都是要有的)
- 2.获取
FragmentManager
,通过getSupportFragmentManager()
方法- 3.开启一个事务,通过
FragmentManager
的beginTransaction()
开启,得到FragmentTransaction
对象- 4.通过
FragmentTransaction
对象的add/replace/remove
方法来实现动态管理碎片- 5.提交事务,通过
FragmentTransaction
对象的commit()
方法
还是用这个标题栏加内容栏做示例,fragment的代码和xml布局就不修改了,和上面一样,我们修改一下Activity的布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="50dp"/>
<LinearLayout
android:orientation="vertical"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
然后在Activity中获取FragmentMananger,获取FragmentTransanction,再调用相关的方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
}
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.title, new TitleFragment());
transaction.add(R.id.content,new ContentFragment());
transaction.commit();
}
}
这是基本的演示,把这些逻辑放一个按钮里面,就能实现按下按钮去动态管理碎片了。
Fragment生命周期
- onAttach:碎片和活动建立关联时调用
- onCreate
- onCreateView:碎片创建视图(加载布局)时调用
- onActivityCreated:确保与碎片相关联的活动已经创建完毕时候调用
- onStart
- onResume
- onPause
- onStop
- onDestroyView:与碎片关联的视图被移出时调用
- onDestroy
- onDetach:碎片和活动解除关联时候调用
(用一下学姐的图。。)
Activity的FragmentManager负责调用队列中Fragment的生命周期方法,只要Fragment的状态与Activity的状态保持了同步,托管Activity的FragmentManager便会继续调用其他生命周期方法以继续保持Fragment与Activity的状态一致。
自己测试的结果是这样的。。略微有些不一样(1.onStart竟然是Fragment先于Activity执行,2.Activity的onCreate最先执行),大框对应的依次是启动、按下主屏幕键、重新打开界面和按后退键:
最后查阅资料,自己体验之后,静态和动态添加的碎片这些打印结果是不一样的。上面那张图我们是动态使用。下面试了一下静态使用碎片,区别在于Activity的onCreate执行顺序:
onCreate的位置为什么出现这样细微的区别,应该在于xml的布局应该会在Activity的onCreate之前就已经开始执行了,细致的原理后面再来补充吧。
和网上查到结果不一致的地方依旧在于onStart的位置.....这个或许是SDK的变更?
Fragment和Activity通信
- Bundle——
setArguments(bundle)
和getArguments()
对于静态碎片,还可以使用第一行代码给出的方法:
RightFragment rightFragment = (RightFragment) getSupportFragmentManger().findFragmentById(R.id.right_fragment);
(1.如果是静态生成fragment,获取fragment实例用getFragmentManager().findFragmentById
2.如果是java代码动态生成fragment,获取fragment实例直接new 一个就好了 没必要用getFragmentManager().findFragmentById)
- 回调接口的方法,
listener = (MyListener) getActivity
网友评论