文章目录
1.碎片是什么
碎片是一种可以嵌入在活动中的UI片段,它能够使程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的十分广泛。(碎片和活动是十分相似的,两者同样都能包含布局,同样都有自己的生命周期,你甚至可以将碎片理解为一个迷你的活动,虽然这个迷你的活动有可能是和普通活动一样大的。碎片的作用实质上就是可以在一个屏幕中有多个独立的UI界面)
2.碎片的使用方法
在活动中引入碎片共有两种方法:1.静态引入;2.动态引入。
2.1静态引入碎片
1.给碎片建立布局。
2.创建碎片的java类(该类需继承Fragment类)。
3.在活动布局中引入该碎片(用android:name属性来确定是哪个碎片)。
示例:
//步骤一
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:text="Button"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
//步骤二
public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.left_fragment,container,false);//加载碎片的布局
return view;
}
}
//步骤三
<fragment
android:id="@+id/left_fragment"//注意:这里必须要给碎片起名字,否则程序将崩溃
android:name="com.example.temp02.LeftFragment"//用碎片类的完整路径进行绑定
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
2.2动态引入碎片
1.给碎片建立布局。
2.创建碎片的java类。(该类需继承Fragment类)
3.在活动的布局中准备碎片存放的布局。
4.在活动的代码中先获取碎片的Manager实例,再获得碎片的Transaction实例,再调用replace()方法向准备好的布局中引入碎片,再调用commit()方法即可完成动态引入碎片。
示例:
//步骤一
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:text="This is right fragment"
android:textSize="30sp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
//步骤二
public class RightFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.right_fragment,container,false);
return view;
}
}
//步骤三
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
//步骤四
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.replace(R.id.right_layout,new RightFragment());
transaction.commit();
2.3再碎片中模拟返回栈
在上述的代码中我们成功的在Fragment布局中引入了碎片,但当我们点击Back键后程序就会直接退出。那么如果我们想要模拟类似于返回栈的功能,点击Back回到上一状态该怎么办呢。
答:实际上非常简单,我们只需在步骤四中调用commit()方法之前先调用addToBackStack()方法即可。
示例:
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.replace(R.id.right_layout,new RightFragment());
transaction.addToBackStack(null);//将该碎片加入返回栈
transaction.commit();
2.4碎片和活动之间进行通信
实际上碎片和活动并没有明显的方式直接进行通信。所以如果想要在活动中调用碎片里的方法就要先获得碎片的实例,同理如果想要在碎片中调用活动里的方法就要先获得活动的实例。
示例:
//在活动中获取碎片实例
LeftFragment leftFragment=(LeftFragment) getSupportFragmentManager().findFragmentById(R.id.left_fragment);
//在碎片中获取活动实例
MainActivity activity=(MainActivity) getActivity();
现在还有一个问题,那就是碎片该怎样和碎片进行通信呢?
答:首先在一个碎片里取得和它相关联的活动的实例,再通过该活动去获取另一个碎片的实例,这样也就实现了碎片与碎片之间的通信。另外,如果要在碎片中使用Context对象时,也可以调用getActivity()方法,应为获取到的活动本身就是一个Context对象。
现在这里还有一个问题,那就是在上节中如果我们采用的是动态引入碎片的方式,那么该碎片就是没有id的,那么活动该怎样和这类碎片取得通信呢?
3碎片的生命周期
和活动一样碎片也有自己的生命周期。
3.1碎片的状态
每个碎片在其生命周期内最多会经历4个状态。
1.运行状态
当一个碎片是可见的,并且和它相关联的活动正处于运行状态时,该碎片也处于运行状态。
2.暂停状态
当一个活动进入暂停状态时,和它相关联的活动也处于暂停状态。
3.停止状态
当一个活动进入停止状态时,和它相关联的活动也处于停止状态。或者调用FragmentTransaction的remove()或replace()方法将碎片从活动中移除,但在事务提交之前调用了addToBackStack()方法,这时碎片也会进入停止状态。
4.销毁状态
碎片总是依附于活动而存在的,因此当活动销毁时,与它相关联的碎片也会进入销毁状态。或者调用FragmentTransaction的remove()或replace()方法将碎片从活动中移除,但在事务提交之前并没有调用addToBackStack()方法,这时碎片也会进入销毁状态。
3.2碎片的回调方法
活动的7个回调方法,碎片几乎都有,不过碎片还提供了一些附加的回调方法,我们就来重点看看这些新增的回调方法。
onAttach():当碎片于活动建立联系时调用。
onCreateView():为碎片加载布局时调用。
onActivityCreated():确保于碎片相关联的活动一定已经创建完毕时调用。
onDestoryView():当与碎片相关联的视图被移除时调用。
onDetach():当碎片与活动解除联系时调用。
碎片完整的生命周期如下图所示:
4.动态加载布局的技巧
如果我们想要开发一款App相信大多数人都希望自己的程序能够在手机和平板上都有比较良好的表现,但又不希望大费周章的去开发两个版本,那么如何让一款App在不同的设备上有不同的表现呢?
下面我们就来学习解决这个问题的两种方法。
4.1使用限定符
我们只需要新建一个带限定符的layout文件并在里面重写活动的UI文件,这样程序就可以根据不同的设备加载不同的UI界面了。
示例:
//layout文件下的activity_main.xml文件的内容
<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/left_fragment"
android:name="com.example.temp02.LeftFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
//layout-large文件下的activity_main.xml文件的内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.temp02.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/right_fragment"
android:name="com.example.temp02.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
4.2使用最小宽度限定符
上节内容我们通过使用限定符解决了跟具不同设备加载不同UI界面的问题。但限定符只是定性的对设备做了一个区分,那么我们如果要定量的对设备进行区分该怎样处理呢?
实际上这个问题也是比较容易解决的,我们只需要将像创建的layout-large文件夹更名为layout_sw600dp即可,这样就用屏幕大小为600dp对所有的设备进行了区分。当设备的屏幕大小在600dp以下就调用layout文件夹下的UI文件,当设备的屏幕大小在600dp以上就调用layout-sw600dp
文件夹下的UI文件。
5.Fragment在各种情况下的生命周期
由于Fragment的生命周期与Activity的生命周期有着牵扯,所以把两者的图放到一起作为对比方便大家理解。
Fragment在Activity中replace的生命周期变化
答:新替换的Fragment:onAttach()–>onCreate()–>onCreateView()–>onViewCreated()–>onActivityCreated()–>onStart()–>onResume()。(其中onViewCreated()方法紧跟在onCreateView()方法之后)
被替换的Fragment:onPause()–>onStop()–>onDestoryView()–>onDestory()–>onDetach()。
Fragment在Activity中replace并addToBackStack的生命周期变化
答:新替换的Fragment(还未加入返回栈的):onAttach()–>onCreate()–>onCreateView()–>onViewCreated()–>onActivityCreated()–>onStart()–>onResume()。
新替换的Fragment(已经在返回栈内的):onCreateView()–>onViewCreated()–>onActivityCreated()–>onStart()–>onResume()。
被替换的Fragment:onPause()–>onStop()–>onDestoryView()。
Fragment进入了运行状态
当Fragment进入了运行状态,以下四个生命周期会随着它所属的Activity一起被调用:
onStart(),onResume(),onPause(),onStop()。