美文网首页
Fragment基础

Fragment基础

作者: 啦啦哇哈哈 | 来源:发表于2018-11-03 00:16 被阅读0次

    fragment的产生和应用场景

    产生

    Activity展示界面的局限性:

    1. 界面中的View较多较复杂时候,操作麻烦;
    2. 手机和平板中,展示效果不一致(平板很大,根据手机设计的界面可能会遇到界面被过分拉长,间隙过大等问题)。

    为解决这个问题,可以将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.开启一个事务,通过FragmentManagerbeginTransaction()开启,得到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

    Fragment之间传值

    相关文章

      网友评论

          本文标题:Fragment基础

          本文链接:https://www.haomeiwen.com/subject/vzoatqtx.html