第十九个项目——使用Fragment组织UI页面
实验目的
掌握Fragment组件的使用方法;
掌握Fragment与Activity组件的交互方式;
实验要求
使用Fragment实现新闻列表加载
实验内容
Fragment中文名为片段或碎片,它可视为Activity UI页面中的部分或轻量级的Activity,其具备与Activity相似的生命周期。通过Fragment可将原有的Activity的UI页面进行划分,提升UI页面的可重用性以及适配性。本实验通过Fragment对第七个项目中新闻列表页面进行重构,介绍Fragment的基本使用方法。
使用Fragment时,需要从自定义Fragment子类,并至少需要重写下列三个方法:
onCreate(),与Activity中的onCreate()方法相似,该方法在创建Fragment实例时被回调,
通常进行Fragment中组件的初始化;
onCreateView(),该方法在当需要Fragment绘制UI时被调用,方法需要返回Fragment的UI布局根视图;
onPause(),该方法在用户离开FragmentUI页面时被调用,通常进行数据持久化或组件销毁;
除了上述三个方法必须进行重写外,Fragment还包含了与生命周期相关的其他几个回调函数,详见官方开发文档。
步骤一,打开第七个项目
打开第七个项目,在该项目的基础上完成本次实验。
步骤二,新建NewsListFragment类
在Project窗口中选择app/java文件夹,右击选择【New】->【Fragment】->【Fragment(Blank)】,在弹出的 New Android Component对话框中Fragment Name文本框中输入NewsListFragment, 勾选Create layout XML?、取消勾选Include fragment factory methods?及 Include interface callbacks复选框,点击【Finish】完成新建Fragment的创建, 具体如图1. 新建NewsListFragment所示。

完成新建操作后,在项目中将生成NewsListFragment.java以及fragment_news_list.xml两个文件,分别对应 Fragment的源文件以及布局文件。
使用Fragment重构第七个项目,主要是将原在MainActivity中各回调函数的业务代码相应的迁移到NewsListFragment相应的回调函数中,而原有activity_main.xml布局元素(除根视图元素外)也可一并迁移至fragment_news_list.xml文件中。
/**
* A simple {@link Fragment} subclass.
*/
public class NewsListFragment extends Fragment {
public NewsListFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_news_list,
container, false);
}
}
步骤三,更改fragment_news_list.xml布局文件
将第七个项目中activity_main.xml布局文件中的ListView标签剪切并复制到fragment_news_list.xml文件中,具体代码如下所示。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/lv_news_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:scrollbars="none"
android:layout_margin="8dp"
android:divider="@android:color/transparent"
android:dividerHeight="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
步骤四,修改NewsListFragment类定义
在NewsListFragment中实现新闻列表加载功能,主要思路是将原MainActivity中的业务代码逐一剪切复制到NewsListFragment当中。
1. 将titles、newsAdapter等对象声明复制到NewsListFragment中
将titles、newsList、newsAdapter等对象申明从MainActivity剪切复制到NewsListFragment中。
2. 将initData()方法复制到NewsListFragment中
将initData()方法定义从MainActivity剪切复制到NewsListFragment中。
3. 重写NewsListFragment的onCreate()方法
在NewsListFragment类中重写onCreate()方法,在其中调用initData()方法进行新闻列表数据初始化。
4. 重写NewsListFragment的onCreateView()方法
onCreateView()方法在Fragment绘制UI时被回调,该方法返回值为完成布局渲染的根视图元素。 为方便加载布局,该方法包含了三个参数:
LayoutInflater inflater,用于加载布局的LayoutInflater对象;
ViewGroup container,Fragment加载的布局应嵌入进的ViewGroup对象;
Bundle savedInstanceState,初始化所需的Bundle对象;
在NewsListFragment的onCreateView()方法中,首先,通过getActivity()获取到与绑定当前Fragment 的Activity对象,并将其作为Context上下文对象进行保存,便于后续使用;其次,通过LayoutInflater对象加载了fragment_news_list布局;最后,通过加载好的布局绑定ListView控件对象,并设置该对象所需的NewsAdapter适配器。
public class NewsListFragment extends Fragment {
private Context context = null;
private String[] titles = null;
private String[] authors = null;
private String[] contents = null;
private TypedArray images;
private List<News> newsList = new ArrayList<>();
private NewsAdapter newsAdapter = null;
private ListView lvNewsList;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
context = getActivity();
View rootView = inflater.inflate(R.layout.fragment_news_list,
container, false);
lvNewsList = rootView.findViewById(R.id.lv_news_list);
newsAdapter = new NewsAdapter(context,
R.layout.list_item,
newsList);
lvNewsList.setAdapter(newsAdapter);
return rootView;
}
private void initData() {
int length;
titles = getResources().getStringArray(R.array.titles);
authors = getResources().getStringArray(R.array.authors);
images = getResources().obtainTypedArray(R.array.images);
if (titles.length > authors.length) {
length = authors.length;
} else {
length = titles.length;
}
for (int i = 0; i < length; i++) {
News news = new News();
news.setTitle(titles[i]);
news.setAuthor(authors[i]);
news.setImageId(images.getResourceId(i, 0));
newsList.add(news);
}
}
}
完成将MainActivity的代码复制到NewsListFragment后,MainActivity类定义代码如下所示。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
步骤五,加载Fragment
在Activity中加载Fragment有2种方式:
静态加载,在Activity对应的布局中使用标签进行静态加载;
动态加载,在Activity中使用FragmentManager、FragmentTransaction动态对Fragment进行数据加载及绑定;
本实验中使用静态加载的方式加载Fragment,打开activity_main.xml布局文件,由于在步骤三 中已经将原ListView标签从activity_main.xml中剪切复制到fragment_news_list.xml中,因此直接在 activity_main.xml根视图元素中加入标签,并通过android:name属性指定 所需加载的Fragment类名(包含包名),最终的布局文件代码如下所示。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context=".MainActivity">
<fragment
android:name="com.glriverside.xgqin.listviewdemo.NewsListFragment"
android:id="@+id/news_list"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
步骤六,编译并运行项目
编译并运行项目,其执行效果与第七个项目相同。
附:Fragment动态加载
动态加载Fragment需要使用FragmentManager、FragmentTransaction两个组件。动态加载Fragment需要指定对应的ViewGroup视图容器,并通过FragmentTransaction完成事务操作。
1. 首先调整activity_main.xml布局文件
在activity_main.xml布局文件中,需要定义ViewGroup视图容器作为动态加载Fragment的根视图容器, 在本实验中,使用ConstraintLayout作为根视图容器,并指定其id属性为fragment_container, 具体代码如下所示。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
2. 修改MainActivity的onCreate()方法
在Fragment 静态加载方式中,通过在布局文件中指定,当Activity被实例化时, 指定的Fragment将被实例化,且该Fragment对象对应的onCreate()、onCreateView()方法会被回调执行。
动态加载Fragment则需要通过FragmentTransaction碎片事务组件完成。 首先,需要获取FragmentManager对象; 其次,调用FragmentManager对象的beginTransaction()方法获得FragmentTransaction对象;在此基础上 调用FragmentTransaction对象的相应方法添加、替换Fragment至指定的ViewGroup视图容器;最后, 调用FragmentTransaction对象的commit()方法提交碎片事务,执行Fragment加载操作。
在该过程中,以下几个方法尤为重要:
getSupportFragmentManager(),获取FragmentManager对象;
FragmentManager.beginTransaction(),开始碎片事务,获得FragmentTransaction对象;
FragmentTransaction.add()或FragmentTransaction.replace(),
添加或替换Fragment至指定ViewGroup视图容器;
FragmentTransaction.addToBackStack(),添加Fragment至返回栈;
FragmentTransaction.commit(),提交碎片事务;
如下代码所示,首先获取了FragmentManager对象,并开始FragmentTransaction碎片事务,再将实例化的NewsListFragment对象通过FragmentTransaction.add()方法添加到R.id.fragment_container视图容器中,最后通过FragmentTransaction.commit()提交碎片事务,完成Fragment动态加载操作。
public class MainActivity extends AppCompatActivity {
FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
NewsListFragment newsListFragment = new NewsListFragment();
ft.add(R.id.fragment_container, newsListFragment);
ft.commit();
}
}
实验小结
通过本次实验,你应该掌握了如下知识内容:
使用Fragment组织UI界面及逻辑;
使用FragmentManager、FragmentTransaction进行Fragment动态加载;
Last updated
Was this helpful?