一、碎片是什么
碎片(Fragment)是一种可以嵌入在活动中的UI片段,他可以让程序更加合理充分的利大屏幕空间,因此在平板上应用十分广泛,由于手机和平板在屏幕大小差距上让同样的界面在视觉效果上有较大的差异,比如在一些界面上手机看起来非常美观,但在平板电脑上可能会有控件被过分拉长的1情况,影响美观。
在手机效果:
没用碎片在平板效果:
用碎片在平板效果:
二、碎片的使用方式
1、碎片的简单用法:
新建一个左侧碎片布局 fragment_left.xml,代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="按钮"/>
</LinearLayout>
然后新建右侧碎片布局fragment_right.xml,代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#00ff00">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="这是右边的fragment"/>
</LinearLayout>
将布局的背景色设置成绿色,并放置了一个 TextView 用于显示一段文本
LeftFragment 的代码如下所示:
建议使用 support-v4 库中的 Fragment,因为它可以让碎片在所有 Android 系统版本中保持功能一致性
public class LeftFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_left, container, false);
return view;
}
}
代码讲解:这里仅仅是重写了 Fragment 的 onCreateView()方法
然后在这个方法中通过 LayoutInflater 的 inflate()方法将刚才定义的 fragment_left 布局动态加载进来
接着我们用同样的方法再新建一个 RightFragment:
public class RightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_right, container, false);
return view;
}
}
接下来修改 activity_mian.xml 中的代码,如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/fragment_left"
android:name="com.wonderful.myfirstcode.inquiry_fragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<fragment
android:id="@+id/fragment_right"
android:name="com.wonderful.myfirstcode.inquiry_fragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
可以看到,我们使用了<fragment>标签在布局中添加碎片
通过 android:name 属性来显式指明要添加的碎片类名,注意一 定要将类的包名也加上
这样最简单的碎片示例就已经写好了,运行一下程序,(平板上)效果如图:
2、动态加载碎片
碎片真正的强大之处在于,它可以在程序运行时动态地添加到活动当中,根据具体情况来动态地添加碎片,你就 可以将程序界面定制得更加多样化。
在上一节代码的基础上继续完善,新建 fragment_another_right.xml,代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffff00">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="这是另外一个右边的fragment"/>
</LinearLayout>
然后新建 AnotherRightFragment 作为另一个右侧碎片,代码如下所示:
public class AnotherRightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_another_right, container, false);
return view;
}
}
接下来看一下如何将它动态地添加到活动当中。修改 activity_mian.xml,代码如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/fragment_left"
android:name="com.wonderful.myfirstcode.inquiry_fragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<!--
<fragment
android:id="@+id/fragment_right"
android:name="com.wonderful.myfirstcode.inquiry_fragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
-->
</LinearLayout>
可以看到,现在将右侧碎片放在了一个 FrameLayout 中
下面在代码中向 FrameLayout 里添加内容,从而实现动态添加碎片的功能
修改 Activity 中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
replaceFragment(new RightFragment());//默认右边布局
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button:
replaceFragment(new AnotherRightFragment());//点击按钮之后改变的布局
break;
default:
break;
}
}
private void replaceFragment(Fragment fragment){
// 获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
// 开启事务
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 添加或替换碎片
transaction.replace(R.id.right_layout,fragment);
// 提交事务
transaction.commit();
}
}
上述代码,给左侧碎片中的按钮注册了一个点击事件
调用 replaceFragment() 方法动态添加碎片
结合代码可看出,动态添加碎片主要分为 5 步:
1. 创建待添加的碎片实例
2. 获取 FragmentManager,在活动中可以直接调用 getSupportFragmentManager()方法得到
3. 开启一个事务,通过调用 beginTransaction()方法开启
4. 向容器内添加或替换碎片,使用 replace() 方法实现,需要传入容器的 id 和待添加的碎片实例。
5. 提交事务,调用 commit()方法来完成
重新运行程序,效果如图:
3、 在碎片中模拟返回栈
点击按钮添加了一个碎片之后,按下 Back 键程序就会直接退出
如果这里我们想模仿类似于返回栈的效果,按下 Back 键可以回到上一个碎片,该如何实现呢?
FragmentTransaction 中提供了一个 addToBackStack() 方法
可以用于将一个事务添加到返回栈中,修改 Activity 中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
. . .
private void replaceFragment(Fragment fragment){
// 获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
// 开启事务
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 添加或替换碎片
transaction.replace(R.id.right_layout,fragment);
// 用于描述返回栈的状态
transaction.addToBackStack(null);
// 提交事务
transaction.commit();
}
}
在事务提交之前调用了 FragmentTransaction 的 addToBackStack() 方法
它可以接收一个名字用于描述返回栈的状态,一般传入 null 就OK
4、碎片和活动之间进行通信
为了方便碎片和活动之间进行通信,FragmentManager 提供了一个类似于 findViewById() 的方法
专门用于从布局文件中获取碎片的实例。在活动中调用碎片里的方法:
RightFragment rightFragment = (RightFragment) getFragmentManager().findFragmentById(R.id.right_fragment);
在碎片中调用活动里的方法:通过调用 getActivity()方法来得到和当前碎片相关联的活动实例
代码如下所示:
MainActivity activity = (MainActivity) getActivity();
5、碎片的生命周期
和活动 Acitvity 相似,Fragment 类中也提供了一系列的回调方法,以覆盖碎片生命周期的每个环节。其中,活动中有的回调方法,碎片中几乎都有,不过碎片还提供了一些附加的回调方法,重点来看下这几个回调:
- onAttach() 当碎片和活动建立关联的时候调用。
- onCreateView() 为碎片创建视图(加载布局)时调用。
- onActivityCreated() 确保与碎片相关联的活动一定已经创建完毕的时候调用。
- onDestroyView() 当与碎片关联的视图被移除的时候调用。
- onDetach() 当碎片和活动解除关联的时候调用。
另外,在碎片中你也可以通过onSaveInstanceState()方法来保存数据
因为进入停止状态的碎片有可能在系统内存不足的时候被回收
保存下来的数据在 onCreate()、onCreateView() 和 onActivityCreated()这三个方法中
你都可以重新得到,它们都含有一个 Bundle 类型的 savedInstanceState 参数
到此,简单的碎片开发结束,我会在下一个阶段 碎片的最佳实践为大家搭建一个简易版的新闻应用;
谢谢支持!!!