嗨!又和大家见面了(每次都是这个开场白有点瓜,,下次换一个-。+),之前我们介绍过Activity,他在UI显示和用户交互的过程中起着重要的作用,但是除了Activity之外,我们还有一个类,也负责同样的功能,他就是Fragment,相信大家也用到过,今天我们详细的讲解一下这个Fragment类。
一、产生意义
1.为了适配不同尺寸的手机以及平板和手机的适应。
这个应该很好理解:我们以前在做应用开发时候,首先需要先针对手机开发一套App,然后在针对平板的尺寸开发另一套App(布局修改),但是这样很捞啊,不但麻烦,而且也做了很多无用功,而Fragment的出现完美的解决了这个问题:Fragment可以被放在Activity的布局中,使我们的视图是由一块块Fragment组成的,这样我们可以根据尺寸的不同进行Fragment的调整。从而解决上述问题。
2.减轻Activity负担。
Fragment也是有自己的生命周期的,而且由于跟Activity绑定,有些生命周期是和Activity同步的(onStart、onResume之类),所以我们的一些在Activity进行用户操作的逻辑代码,可以写到Fragment中,减少了Activity的代码量。
二、生命周期
直接上图可能更明确些:
这里有两张图(反正都不是我画的-。+,但是这两张图是真的棒,所以我粘贴过来了):
第一张是Fragment相对比较完整的生命周期,我们注意到当Fragment即将失去焦点时(绿色方框下面),他有两种情况,一种是将Fragment添加到退回栈(back Stack),还有一种情况是没有添加。他们在进行到onDestroyView方法之后生命周期是不相同的,这里只是稍微提一下,今天我们讲的不涉及到退回栈。
第二张图是Activity生命周期方法和Fragment生命周期方法的联系,我们注意到中间的几个方法Activity和Fragment是同步的。
接下来简单地描述一下相关生命周期方法:
- onAttach:让Fragment和Activity关联,此时关联的Activity已经被传进来,可以通过getActivity获取Activity实例(但是有些时候使用需要强转)。
- onCreate:在Fragment实例被创建时候调用。
- onCreateView:Fragment视图创建过程。
- onViewCreated:当onCreateView方法返回后立即调用,此时Fragment的层次结构还没有添加到父节点上(这个方法一般没有被提到,但是我想在这里提一下。)
- onActivityCreated:当Activity创建完成,而且该Fragment的层次结构也被实例化,调用。
- onStart:在Fragment可见的时候调用,通常与Activity的生命周期相关联。
- onResume:当Fragment可见而且可获取焦点时调用,通常与Activity的生命周期相关联。
- onPause:当Fragment失去焦点时调用,通常与Activity的生命周期相关联。
- onStop:当Fragment不可见时候调用,通常与Activity的生命周期相关联。
- onDestroyView:当Fragment与其先前创建的视图分离时调用。
- onDestroy:当Fragment实例被销毁时调用。‘
- onDetach:Fragment解除关联。
浓缩了半天,可是写完发现话还是很多,简单总结一下:
我们把这些方法分成三大类:
- 创建
- 与Activity同步的方法
- 销毁
其中创建的相关方法为:onAttach,onCreate,onCreateView,onViewCreated,onActivityCreated。这里面说的创建是关于Fragment视图和实例的创建过程以及Fragment实例与Activity绑定的过程。
与Activity同步的方法就很简答了,他们与Activity的对应生命周期方法是同步执行的:onStart,onResume,onPause,onStop。
销毁的相关方法为:onDestroyView,onDestroy,onDetach。销毁是对Fragment实例、视图的销毁,以及Fragment与Activity取消关联。
以上是对生命周期的讲解,我们可以告一段落了。
三、Fragment使用
Fragment分为静态使用和动态使用的过程:
静态使用:
关于静态使用我个人感觉用处不大,而且没什么好讲的,因为使用的时候还是动态使用的比较多,我们就简单看一下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity"> <fragment android:id="@+id/f1" android:name="zy.pers.fragmenttext.OneFragment" android:layout_width="wrap_content" android:layout_height="match_parent" > </fragment> <fragment android:id="@+id/f2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:name="zy.pers.fragmenttext.TwoFragment"/> </LinearLayout>
这是我们MainActivity的布局文件,很简单,只是往里面放入了两个碎片,
然后我们还需要这两个碎片:
public class OneFragment extends Fragment { private static final String TAG = "OneFragment"; ...... @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { Log.e(TAG, "onCreateView: "); View view = inflater.inflate(R.layout.one_fragment, container, false); return view; } ...... }
这是OneFragment的类。
这里我们只是需要创建出来显示,并没有实现哪些功能,所以我们只重写了onCreateView方法,在里面调用了inflate方法加载了布局。
所以我们还需要一个布局文件:
<?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:background="@color/colorPrimary"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="OneFragment" android:textAllCaps="false" android:textColor="@color/whilte" android:textSize="28sp" android:gravity="center"/> </LinearLayout>
这是OneFragment的布局文件,上了个颜色,放了一个TextView。
TwoFragment同一。
现在我们启动程序看一下效果:
看着很蠢。。。。因为他就是这么简单。我们直接看动态添加:
动态使用:
我们刚才静态使用是被锁死的布局,也就是说他无法改变,而动态布局是我们动态添加Fragment,这里要用到一个熟悉的布局——FrameLayout。我们直接看代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity" > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/fra1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="addone" android:textAllCaps="false" /> <Button android:id="@+id/fra2" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="visible" android:text="addtwo" android:textAllCaps="false" /> </LinearLayout> <FrameLayout android:id="@+id/frame" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
在布局中添加了一个线性布局和一个帧布局。线性布局中放置了两个按钮,一个用来添加OneFragment,一个用来添加TwoFragment。
findViewById(R.id.fra1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager manager = getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); transaction.add(R.id.frame, oneFragment).commit(); } }); findViewById(R.id.fra2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager manager = getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); transaction.add(R.id.frame, twoFragment).commit(); } });
这是我们写在MainActivity中用来添加Fragment的代码(这几个方法下面会详细介绍的)。
效果:
上面的代码只是展示一下Fragment的使用,里面提到了两个类:FragmentManger和FragmentTransaction:
- FragmentManager类负责管理Fragment。通过getFragmentManager和getSupportFragmentManager方法获取。
- FragmentTransaction类主要负责对Fragment的添加,移除,替换,显示,隐藏等操作。
我们下面具体介绍一下FragmentTransaction类(FragmentManager类详细在下一篇中介绍。):
四、FragmentTransaction相关方法。
我们提到了FragmentTransaction的作用,上面也用到了add这个方法,那我们先从add方法开始讲起吧:
以下全部都是文档解释翻译的(自己翻译的,精神可嘉-。+)
- add:将Fragment添加到Activity状态中,这个Fragment可以选择创建自己的view,添加到Activity的容器视图中(如果onCreateView返回非空)。
- remove:将Fragment移除,如果他有view,那么同时移除他的view。
- replace:替换容器中已存在的Fragment,这个方法的效果和先调用remove再调用add方法相同。
- hide:隐藏已存在的Fragment,这个方法只和那些视图被他添加进容器中的Fragment有关(因为这个方法效果是隐藏视图)。
- show:显示之前隐藏的Fragment,这个方法只和那些视图被他添加进容器中的Fragment有关(因为这个方法效果是显示视图)。
- detach:从UI中分离Fragment,效果和将Fragment放入退回栈相同(退回栈下一篇会提到)。Fragment的UI被移除,但是FragmentManager还是管理着他的状态。这个状态只是销毁Fragment的视图。
- attach:在Fragment从UI中分离之后,重新创建其视图结构,并和UI关联,且显示在界面上。
以上便是FragmentTransaction所常用到的几个方法,他们都是负责Fragment的显示状态。主要的话我用红字标出来了,良心翻译,大家应该能够看懂。
有一点一定要说一下:上面的attach和detach千万不要跟Fragment的生命周期方法搞混了!重要的事说三遍!!
五、FragmentTransaction方法对应的Fragment生命周期方法
我们上面说到了FragmentTransaction的相关方法,我们可以看到都是对Fragment状态的调整(创建、显示、隐藏、销毁),这不正是对应着Fragment的生命周期么,以下是对应方法所涉及到的生命周期:
add:onAttach -> onCreate -> onCreateView -> onViewCreated(如果同时创建了view视图会调用-> onActivityCreated -> onStart->onResume
remove:onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
replace:这个就不多说了,上面两个合体。
hide/show:这两个方法不会调用Fragment任何生命周期方法:因为他只是显示和隐藏Fragment,有同学可能会说会调用onPause -> onStop 方法,但是不会。因为这几个对应的方法都是和Activity生命周期方法绑定的,而我们只是隐藏了Fragment,但是Activity还是在获取课焦点的状态(onResume),所以不会。
detach:onPause -> onStop -> onDestoryView 。
attach:onCreateView -> onViewCreated -> onActivityCreated -> onStart -> onResume
以上便是我们今天所涉及的全部内容,关于下一篇中会给大家带来关于Fragment更多的内容:Fragment详解(2)
喜欢的朋友可以关注一波,有不同观点和建议的可以评论留言。
谢谢大家支持!