第6章 使用Fragments构建动态UI

为了在Android创建一个动态的多面的用户界面,你需要封装UI组件和activity的行为到一种可以相互交换的act的模块中。我们能使用Fragment类创建这些模块,这行为有点像一个嵌套的act,它可以定义自己的布局和管理自己的生命周期。Fragment的好处已经越发明显,它是Android3.0新增的API。当一个fragment指定它的布局,它能以不同的组合配置到act中,为不同的屏幕大小修改你的布局配置,一个小屏幕可能只显示一个fragment,而在大屏幕中可能显示2个或2个以上的fragment。本章说明怎样使用fragment创建动态的用户体验并为不同屏幕大小的设备优化用户体验,同时继续支持例如Android1.6这样的老版本。以下是内容预览:

1. 使用Android支持的库

通过绑定Android支持库,学习怎样使用近期新版本的APIs

2. 创建一个Fragment

学习怎样创建fragment并实现一些基本行为

3.构建一个灵活的UI

学习怎样为不同的屏幕提供不同的fragment配置布局

4. 与其他Fragment通信

学习如何为fragment设置通信路径来与启动fragment或Activity通信

6.1 使用Android支持库

Android支持库(Support Library)提供了一个支持API库的Jar文件,这个库允许你在早期的系统版本中使用近期系统版本中的API,一个好消息就是Support Library提供一个Fragment版本的APIs,所以我们可以在1.6-3.0之间的系统版本也能使用它了。本小节主要说明怎样设置Support Library来支持fragments让我们的低系统版本的应用夜支持动态UI。

6.1.1根据支持库设置我们的工程

1. 使用SDK Manager下载Android Support包,如图6-1所示:

图6-1 下载Android Support的截图

2. 在你的Android工程中创建一个libs目录

3.定位你的jar文件,把你想要使用的库复制到ligs/目录中,例如

<sdk>/extras/android/support/v4/android-support-v4.jar

4. 更新你的manifest文件设置最小API Level为4,目标API Level为15(截止此刻最新的系统版本4.0.3)

<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />

6.1.2导入我们支持库的APIs

Support Library包含各种各样的APIs,这些APIs可能你很想使用,为了考虑使用低系统版本的用户,可能他们的系统中没有此APIs。SL就是专为它而生。你能找到所有关于SL的API的文档,请参考官方API文档中的android.support.v4.*

当你使用了SL后,特别注意如果你自己的开发环境使用的是新系统,并使用了新的Fragment类,千万注意兼容性,不是所有设备都跟你一样使用的是新系统,你应该导入如代码清单6-1所示:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
...

代码清单6-1

6.2 创建一个Fragment

你可以认为一个Fragment作为act模块化的一个部分,它有其自己的生命周期,接收它自己的输入事件,在该act运行时,你可以添加或删除。本节说明如何在支持库的情况下使用Fragment类,我们的应用程序仍然运行旧的Android 1.6系统版本上。当然如果你是直接声明你的应用支持的最小API level为11(android 3.0)的话,就不需要使用支持库了,不过这种做法目前不可取。

6.2.1创建一个Fragment类

首先我们需要继承Fragment类,然后重写关键的生命周期方法,就像Activity一样。实际上我们需要重写的方法仅仅是onCreateView()这一个方法,因为必须在这里创建一个布局,Fragment才能正确运行,我们可以参考下面的代码清单6-2:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.ViewGroup;public class ArticleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 为这个fragment填充布局return inflater.inflate(R.layout.article_view, container, false);}
}

代码清单6-2

就像activity一样,一个fragment也应该实现其他声明周期的回调方法,以允许你管理状态(例如从activity中添加或删除),例如,当act调用onPause()时,在act中的任意fragments也将接收到onPause()回调。关于fragment更详细的使用方法,会在API框架中讲解。

6.2.2使用XML添加一个Fragment到Activity

fragments是可复用的,模块化的UI组件,每一个Fragment类实例都必须和父对象FragmentActivity关联起来。你能通过在activity中的layout  XML文件来定义每个fragment以完成这个关联。注意如果你支持的最低系统版本为API Level 11那么你可以直接使用Activity,因为FragmentActivity是专门为早期系统版本,并使用支持库中的Fragment而创建的。下面是一个布局文件的例子,当你设备的屏幕为“large”时,允许你在一个act中添加2个fragments。如代码清单6-3所示:

res/layout-large/news_articles.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="fill_parent"><fragment android:name="com.example.android.fragments.HeadlinesFragment"android:id="@+id/headlines_fragment"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent" /><fragment android:name="com.example.android.fragments.ArticleFragment"android:id="@+id/article_fragment"android:layout_weight="2"android:layout_width="0dp"android:layout_height="match_parent" /></LinearLayout>

代码清单6-3

以下是在代码中如何使用以上的layout xml文件,如代码清单6-4所示:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;public class MainActivity extends FragmentActivity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.news_articles);}
}

代码清单6-4

注意:当你通过xml来定义fargment时,在运行时是不能移除的。下一小节我们会讲解如何动态与用户交互

6.3 创建一个灵活的Fragment

当你为了支持广泛的屏幕大小而设计你的App时,你能在不同的布局配置中重用你的fragments以优化各种屏幕大小的用户体验。例如,某个时刻在手机上显示一个fragment,相反的在平板中由于屏幕更大可能显示更多的fragment。

下面让我们看一下图6-2:

图6-2 平板和手机上使用Fragment的不同之处

FragmentManager类提供添加,删除,替换fragment的方法,可以在Activity运行时的使用,以创建一个动态的用户体验。

6.3.1在Activity运行时添加一个Fragment

与其用xml定义fragments ,不如在运行时动态添加更灵活。如果你计划在act的生命周期中改变fragments ,那么使用动态机制是必要的。例如执行添加或移除一个fragment的事务处理,我们必须使用FragmentManager类创建一个FragmentTransction,它提供添加,移除,替换fragment的各种APIs。如果你的act允许fragments被移除和替换的话,那么你应该添加初始的(也可理解为原始父类)fragment到act的onCreate()中。一个很重要的规则就是当处理fragments,尤其是那些运行时添加的fragment时,必须有一个View容器包裹fragment。我们依旧使用上一节的布局xml文件但仅仅显示一个fragment,因为我们支持的是layout而不是layout-large,由于我们使用代码动态添加fragments,所以XML中是不能有fragment节点声明的。并且XML中只有一个FrameLayout,如代码清单6-5所示:

res/layout/news_articles.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent" />

代码清单6-5

在我们的activity中,使用支持库APIs调用getSupportFragmentManager()来获得一个FragmentManger。然后调用beginTransaction()创建一个FragmentTransaction以通过它的add()方法来添加一个fragment。你能在act中使用同一个FragmentTransaction执行多个fragment处理事务。当你确定改变时,需要调用commit()来提交我们的操作。具体操作,如代码清单6-6所示:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;public class MainActivity extends FragmentActivity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.news_articles);//检查FrameLayout是否为空if (findViewById(R.id.fragment_container) != null) {// 如果我们从先前的状态恢复,那么我们不需要做任何事,直接返回if (savedInstanceState != null) {return;}//创建一个HeadlinesFragment对象,光盘资源中有此类的实现HeadlinesFragment firstFragment = new HeadlinesFragment();// 给fragment设置一个Intent's extras参数
            firstFragment.setArguments(getIntent().getExtras());//添加fragment到'fragment_container'(FrameLayout)
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).commit();}}
}

代码清单6-6

因为fragment在运行时被添加到FrameLayout,而不是我们6.2中使用layout XML文件把fragment写到<fragment>中,所以我们可以动态添加,移除,替换fragment。

6.3.2替换Fragment

替换fragment ,不是用add()而是使用replace()。请记住,当你使用FragmentTransaction执行更换或删除一个fragment交易,它常常是适当允许用户向后导航“撤消”的转变。在你提交之前请调用FragmentTransaction.addToBackStack()方法。当删除或替换一个fragment,并添加回栈的操作时,被删除的fragment已停止(没有被destroyed)。如果用户后退导航,那么fragment恢复并重新启动。如果你不添加addToBackStack(),则当fragment被移除和替换时,直接被destroyed。下面我们看下代码清单6-7:

// 创建fragment并给他一个参数用于确定选择文章的位置
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();//我们需要把文章标题Fragment替换为文章内容Fragment
// 我们添加了addToBackStack(),表示用户向后导航的时候fragment不会被destroyed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);// 提交
transaction.commit();

代码清单6-7

如果在addToBackStack()中传入null,表示你可能更高级的操作,例如使用FragmentManager.BackStackEntry。

6.4 与其他Fragment通信

为了重用Fragment的UI组件,你应该建立一个定义了自己的布局和行为的完全独立并模块化的组件。一旦你定义了这些可重用的Fragment,你可以与Activity相关联,并与应用逻辑连接,以实现整体复合UI。通常情况下,你会想几个Fragment相互通信,例如基于用户事件改变内容。所有Fragment的通信是通过相关的Activity。两个Fragment,不应该直接通信。

6.4.1定义一个接口

为了允许一个Fragment 与Activity通信, 你可以在Fragment类里定义一个接口并在Activity中实现此接口。Fragment在它的onAttach()生命周期方法中捕获接口的实现,然后调用接口方法为了与Activity通信。下面让我们来看下代码清单6-8:

public class HeadlinesFragment extends ListFragment {OnHeadlineSelectedListener mCallback;// 容器Activity必须实现这个接口,用来传递消息public interface OnHeadlineSelectedListener {public void onArticleSelected(int position);}@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);// 确保容器Activity已经实现回调接口,如果没有则会抛出一个异常try {mCallback = (OnHeadlineSelectedListener) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString()+ " must implement OnHeadlineSelectedListener");}}...
}

代码清单6-8

现在fragment能通过调用Activity中的onArticleSelected() 方法来传递消息了。等会我们将展示实现的代码。

例如下面的onListItemClick()方法,当用户点击fragment 中的list item时会调用此方法。我们这个fragment 使用这个回调接口传递事件到父类Activity。如代码清单6-9所示:

 
  @Overridepublic void onListItemClick(ListView l, View v, int position, long id) {//通知父类activity选择的item
        mCallback.onArticleSelected(position);}

代码清单6-9

6.4.2 实现一个接口

为了从fragment接收事件回调, 父类activity必须实现这个在fragment类中定义的接口。例如下面的代码实现了这个接口,如代码清单6-10所示:

public static class MainActivity extends Activityimplements HeadlinesFragment.OnHeadlineSelectedListener{...public void onArticleSelected(Uri articleUri) {//用户从HeadlinesFragment选择文章的标题// do something
    }
}

代码清单6-10

6.4.3 传递消息到Fragment

我们通过Fragment实例的findFragmentById()方法直接获取ArticleFragment。

关于接口的具体实现,下面让我们看下代码清单6-11:

public static class MainActivity extends Activityimplements HeadlinesFragment.OnHeadlineSelectedListener{...public void onArticleSelected(int position) {//用户从HeadlinesFragment选择文章的标题//从 res/layout-large/获得文章 fragmentArticleFragment articleFrag = (ArticleFragment)getSupportFragmentManager().findFragmentById(R.id.article_fragment);if (articleFrag != null) {//如果articleFrag不为空,我们正在使用的是双面板布局(平板设备)//调用 ArticleFragment的这个方法来更新内容
            articleFrag.updateArticleView(position);} else {//否则,我们使用的是单面板(手机设备)//创建fragment并给他传入一个参数用于确定选择文章的位置ArticleFragment newFragment = new ArticleFragment();Bundle args = new Bundle();args.putInt(ArticleFragment.ARG_POSITION, position);newFragment.setArguments(args);FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();//我们需要把文章标题Fragment替换为文章内容Fragment//表示用户可以后退导航
            transaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);//最后需要使用transaction提交
            transaction.commit();}}
}

代码清单6-11

完整的项目下载地址:http://url.cn/J49JRr

本文来自jy02432443,QQ78117253。转载请保留出处,并保留追究法律责任的权利

转载于:https://www.cnblogs.com/tianjian/archive/2012/07/08/2581509.html

第二部分:开发简要指南-第六章 使用Fragments构建动态UI相关推荐

  1. Knockout应用开发指南 第六章:加载或保存JSON数据

    原文:Knockout应用开发指南 第六章:加载或保存JSON数据 加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地 ...

  2. Gradle 2.0 用户指南翻译——第五十六章. 多项目构建

    本文禁止w3cschool转载! 翻译项目请关注Github上的地址:https://github.com/msdx/gradledoc . 本文翻译所在分支:https://github.com/m ...

  3. Gradle 1.12用户指南翻译——第五十六章. 多项目构建

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  4. Java7并发编程指南——第六章:并发集合

    Java7并发编程指南--第六章:并发集合 @(并发和IO流) Java7并发编程指南第六章并发集合 思维导图 项目代码 思维导图 项目代码 GitHub:Java7ConcurrencyCookbo ...

  5. 第六章 使用scikit-learn构建模型

    第六章 使用scikit-learn构建模型 任务6.1 使用sklearn转换器处理数据 6.1.1 加载datasets模块中的数据集 #加载breast_canser数据集 from sklea ...

  6. Kali Linux 无线渗透测试入门指南 第六章 攻击客户端

    第六章 攻击客户端 作者:Vivek Ramachandran, Cameron Buchanan 译者:飞龙 协议:CC BY-NC-SA 4.0 简介 安全强度取决于最弱的部分. – 信息安全领域 ...

  7. PHPUnit袖珍指南 第六章 装置器

    第六章 装置器 编写测试最耗时的部分是边编写设置整个程序到达一个已知状态,而后在测试结束后返回到原始状态.这个已知状态叫做测试的装置器. 在例5中,装置器很简单,只是存储在变量$fixture中的数组 ...

  8. 算法竞赛入门经典(第二版)-刘汝佳-第六章 数据结构基础 习题(12/14)

    文章目录 说明 习题 习6-1 UVA 673 平衡的括号 习6-2 UVA 712 S - 树 习6-3 UVA 536 二叉树重建 习6-4 UVA 439 骑士的移动 习6-5 UVA 1600 ...

  9. 游戏感:虚拟感觉的游戏设计师指南——第六章 输入的测量方法

    这是一本游戏设计方面的好书 转自天:天之虹的博客:http://blog.sina.com.cn/jackiechueng 感谢天之虹的无私奉献 Word版可到本人的资源中下载 第六章输入的测量方法 ...

最新文章

  1. HTML5 使用 JS 生成二维码,带头像
  2. Linux 技巧:让进程在后台可靠执行的几种方法
  3. ASP.NET -- WebForm -- Cookie的使用 应用程序权限设计 权限设计文章汇总 asp.net后台管理系统-登陆模块-是否自动登陆 C# 读写文件摘要...
  4. contentProvider 内容提供者
  5. 手机里语音转文字怎么实现的呢?看完你就明白了
  6. 2006. 差的绝对值为 K 的数对数目
  7. mysql 大于小于不可在一个不等式中同时写
  8. 面经手册 · 第16篇《码农会锁,ReentrantLock之公平锁讲解和实现》
  9. 债券收益率预测模型_股债收益率模型看A股估值 股债收益率模型(EYBY)是一个经典的股市估值模型,其基本思想是将“股票收益率”(EY)与“债券收益率”(BY)进行对比... - 雪球...
  10. 学python多长时间、才能做点东西_如果只有1小时学Python,看这篇就够了
  11. vue官网oracle,Oracle企业可视化解决方案AutoVue系列产品更新至v21.0.1
  12. 数学笔记11——微分和不定积分
  13. 使用Senparc.Weixin SDK搭建微信公众号服务程序
  14. 新人转行IC该怎么选择岗位?(内附各岗位学习视频)
  15. java有关的论述_中国大学MOOC: 以下有关JAVA线程的论述,正确的是()。
  16. 习题 于歆杰 电路_清华大学 电路原理 于歆杰 60讲视频教程
  17. Win8快速关机命令
  18. 查找网络上的计算机快捷键,快捷键查找是ctrl加多少
  19. python 动态仪表盘_利用EXCEL的power pivot+切片器制作动态仪表盘
  20. 微信小程序蓝牙BLE开发——写入一串16进制数据,低字节在前(五)

热门文章

  1. layui遇见的问题
  2. oracle rac 高并发性能_Tomcat 高并发之道原理拆解与性能调优
  3. java中未解决的编译问题_java – 我遇到了这个异常:未解决的编译问题
  4. mysql分组查询学生平均年龄_mysql练习题
  5. 音乐 美术 计算机期末考试表,2021东莞中考音乐美术信息技术合格性考试时间安排...
  6. springboot完成进度条_Springboot从0开始第一周
  7. android 代码水印,Android实现为图片添加水印
  8. wpp助手怎么连接服务器,aewpp.com
  9. mysql 修改字段编码_mysql修改数据库编码字段编码
  10. python安装的模块在pycharm中能用吗_pycharm安装python模块