Android 进阶 Fragment 介绍和使用 (一)
Fragment概述
Fragment是activity的界面中的一部分或一种行为。你可以把多个Fragment们组合到一个activity中来创建一个多面界面并且你可以在多个activity中重用一个Fragment。你可以把Fragment认为模块化的一段activity,它具有自己的生命周期,接收它自己的事件,并可以在activity运行时被添加或删除。
Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。
设计哲学
Android从3.0开始引入fragment,主要是为了支持更动态更灵活的界面设计,比如在平板上的应用。平板机上拥有比手机更大的屏幕空间来组合和交互界面组件们。Fragment使你在做那样的设计时,不需应付view树中复杂的变化。通过把activity的layout分成fragment,你可以在activity运行时改变它的样子,并且可以在activity的后退栈中保存这些改变。
例如:写一个读新闻的程序,可以用一个fragment显示标题列表,另一个fragment显示选中标题的内容,这两个fragment都在一个activity上,并排显示。那么这两个fragment都有自己的生命周期并响应自己感兴趣的事件。于是,不需再像手机上那样用一个activity显示标题列表,用另一个activity显示新闻内容;现在可以把两者放在一个activity上同时显示出来。如下图:
创建Fragment
要创建fragment,必须从Fragment或Fragment的派生类派生出一个类。Fragment的代码写起来有些像activity。它具有跟activity一样的回调方法,比如 onCreate(),onStart(),onPause()和onStop()。实际上,如果你想把老的程序改为使用fragment,基本上只需要把activity的回调方法的代码移到fragment中对应的方法即可。
通常需要实现以上生命周期函数:
onCreate():
当创建fragment时系统调用此方法。在其中你必须初始化fragment的基础组件们。可参考activity的说明。
onCreateView():
当第一次绘制Fragment的UI时系统调用这个方法,必须返回一个View,如果Fragment不提供UI也可以返回null。
注意,如果继承自ListFragment,onCreateView()默认的实现会返回一个ListView,所以不用自己实现。
onPause():
当用户离开Fragment时第一个调用这个方法,需要提交一些变化,因为用户很可能不再返回来。
大多数程序应最少对fragment实现这三个方法。当然还有其它几个回调方法可应该按情况实现之。所有的生命周期回调函数在“操控fragment的生命周期”一节中有详细讨论。
下图为fragment的生命周期(它所在的activity处于运行状态)。
为fragment添加用户界面
fragment一般作为activity的用户界面的一部分,把它自己的layout嵌入到activity的layout中。 有两种方法将一个fragment添加到activity中:
要为fragment提供layout,你必须实现onCreateView()回调方法,然后在这个方法中返回一个View对象,这个对象是fragment的layout的根。
注:如果你的fragment是从ListFragment中派生的,就不需要实现onCreateView()方法了,因为默认的实现已经为你返回了ListView控件对象。
要从onCreateView()方法中返回layout对象,你可以从layoutxml中生成layout对象。为了帮助你这样做,onCreateView()提供了一个LayoutInflater对象。
举例:以下代码展示了一个Fragment的子类如何从layoutxml文件example_fragment.xml中生成对象。
publicstaticclassExampleFragmentextendsFragment{
@Override
publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){
//Inflate the layout for this fragment
returninflater.inflate(R.layout.example_fragment,container,false);
}
}
onCreateView()参数中的container是存放fragment的layout的ViewGroup对象。savedInstanceState参数是一个Bundle,跟activity的onCreate()中Bundle差不多,用于状态恢复。但是fragment的onCreate()中也有Bundle参数,所以此处的Bundle中存放的数据与onCreate()中存放的数据还是不同的。至于详细信息,请参考“操控fragment的生命周期”一节。
Inflate()方法有三个参数:
1.layout的资源ID。
2.存放fragment的layout的ViewGroup。
3.布尔型数据表示是否在创建fragment的layout期间,把layout附加到container上(在这个例子中,因为系统已经把layout插入到container中了,所以值为false,如果为true会导至在最终的layout中创建多余的ViewGroup(这句我看不明白,但我翻译的应该没错))。
现在你看到如何为fragment创建layout了,下面讲述如何把它添加到activity中。
把fragment添加到activity
一般情况下,fragment把它的layout作为activitiy的loyout的一部分合并到activity中,有两种方法将一个fragment添加到activity中:
方法一:在activity的layoutxml文件中声明fragment(静态使用Fragment)
如下代码,一个activity中包含两个fragment:
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragmentandroid:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<fragmentandroid:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
<fragment>中声明一个fragment。
其中android:name属性填上你自己创建的fragment的完整类名。
当系统创建上例中的layout时,它实例化每一个fragment,然后调用它们的onCreateView()方法,以获取每个fragment的layout。系统把fragment返回的view对象插入到<fragment>元素的位置,直接代替<fragment>元素。
注:每个fragment都需要提供一个ID,系统在activity重新创建时用它来恢复fragment们,你也可以用它来操作fragment进行其它的事物,比如删除它。有三种方法给fragment提供ID:
1 为android:id属性赋一个数字。
2 为android:tag属性赋一个字符串。
3如果你没有使用上述任何一种方法,系统将使用fragment的容器的ID。
方法二:在代码中添加fragment到一个ViewGroup (动态的使用Fragment)
这种方法可以在运行时,把fragment添加到activity的layout中。你只需指定一个要包含fragment的ViewGroup。
为了完成fragment的事务(比如添加,删除,替换等),你必须使用FragmentTransaction的方法。你可以从activity获取到FragmentTransaction,如下:
FragmentManager fragmentManager =getFragmentManager()
FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
然后你可以用add()方法添加一个fragment,它有参数用于指定容纳fragment的ViewGroup。如下:
ExampleFragmentfragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container,fragment);
fragmentTransaction.commit();
Add()的第一个参数是容器ViewGroup,第二个是要添加的fragment。一旦你通过FragmentTransaction对fragment做出了改变,你必须调用方法commit()提交这些改变。
不仅在无界面的fragment中,在有界面的fragment中也可以使用tag来作为为一标志,这样在需要获取fragment对象时,要调用findFragmentTag()。
fragment实例:
写一个类继承自Fragment类,并且写好其布局文件,在Fragment类的onCreateView()方法中加入该布局。
之后用两种方法在Activity中加入这个fragment:
第一种是在Activity的布局文件中加入<fragment>标签:
自己定义的fragment类:
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; /**
* Created by jcli on 2015/11/27.
*/
public class TestFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
System.out.println("TestFragment--onCreate");
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
System.out.println("TestFragment--onCreateView");
return inflater.inflate(R.layout.fragment_test, container, false);
} @Override
public void onPause()
{
super.onPause();
System.out.println("TestFragment--onPause");
}
}
Fragment 布局文件:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jcdh.jcli.activitydemo.BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="30sp"
android:gravity="center"
android:text="我是一个 Fragment" /> </FrameLayout>
加载Fragment的Activity:
public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
加载Fragment的Activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jcdh.jcli.activitydemo.MainActivity">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.jcdh.jcli.activitydemo.TestFragment"
android:id="@+id/fragment"
/>
</RelativeLayout>
效果图片:
第二种在Activity的代码中使用FragmentTransaction的add()方法加入fragment(动态使用Fragment):
Actvity的布局文件,有两个按钮用来切换:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jcdh.jcli.myapplication.MainActivity"> <Button
android:id="@+id/first_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:onClick="moveToFragment"
android:text="第一个Fragment" /> <Button
android:id="@+id/second_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/first_btn"
android:onClick="moveToFragment"
android:layout_alignParentTop="true"
android:text="第二个Fragment" /> <fragment
android:id="@+id/first_fragment"
android:name="com.jcdh.jcli.myapplication.FirstFragment"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_below="@+id/first_btn">
</fragment>
</RelativeLayout>
下面看一下集成fragment的Activity类
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.Activity;
import android.os.Bundle;
import android.view.View; public class MainActivity extends Activity { private FirstFragment fristFragment;
private SecondFragment secondFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} private void initView()
{
FragmentManager fm = this.getFragmentManager();
android.app.FragmentTransaction transaction = fm.beginTransaction();
fristFragment = new FirstFragment();
transaction.replace(R.id.first_fragment, fristFragment);
transaction.commit();
}
public void moveToFragment(View view)
{
// 开启Fragment事务
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
switch (view.getId())
{
case R.id.first_btn:
if(fristFragment !=fm.findFragmentByTag("fragmentTag"))
{
// 使用当前Fragment的布局替代first_fragment的控件
transaction.replace(R.id.first_fragment,fristFragment);
}
break;
case R.id.second_btn:
if(secondFragment==null)
{
secondFragment = new SecondFragment();
}
if(secondFragment !=fm.findFragmentByTag("fragmentTag"))
{
transaction.replace(R.id.first_fragment,secondFragment);
}
break;
}
transaction.commit();
}
}
可以看到我们使用FragmentManager对Fragment进行了动态的加载,这里使用的是replace方法~~下一节我会详细介绍FragmentManager的常用API。
注:如果使用Android3.0以下的版本,需要引入v4的包,然后Activity继承FragmentActivity,然后通过getSupportFragmentManager获得FragmentManager。不过还是建议版Menifest文件的uses-sdk的minSdkVersion和targetSdkVersion都改为11以上,这样就不必引入v4包了。
代码中间还有两个Fragment的子类:
FirstFragment 代码:
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; public class FirstFragment extends Fragment { @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); } @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jcdh.jcli.myapplication.FirstFragment"> <!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20sp"
android:gravity="center"
android:background="@android:color/black"
android:textColor="@android:color/white"
android:text="我是第一个Fragment" /> </FrameLayout>
SecondFragment代码:
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; public class SecondFragment extends Fragment { @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); } @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false);
}
}
布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jcdh.jcli.myapplication.FirstFragment"> <!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="30sp"
android:gravity="center"
android:background="@android:color/darker_gray"
android:text="我是第二个Fragment" /> </FrameLayout>
效果图片:
点击第二个按钮切换;
Fragment家族常用的API
Fragment常用的三个类:
android.app.Fragment 主要用于定义Fragment
android.app.FragmentManager 主要用于在Activity中操作Fragment
android.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
a、获取FragmentManage的方式:
getFragmentManager() // v4中,getSupportFragmentManager
b、主要的操作都是FragmentTransaction的方法
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add()
往Activity中添加一个Fragment
transaction.remove()
从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。
transaction.replace()
使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~
transaction.hide()
隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
transaction.show()
显示之前隐藏的Fragment
detach()
会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
attach()
重建view视图,附加到UI上并显示。
transatcion.commit()//提交一个事务
注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。
值得注意的是:如果你喜欢使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
见http://blog.csdn.net/q610098308/article/details/50098971
此文档参考了其它文档,现在也共享出来和大家分享,如有问题可以留言给我
Android 进阶 Fragment 介绍和使用 (一)的更多相关文章
- Android 进阶 Fragment 介绍和使用 (二)
管理fragment 因为FragmentManager的API是在Android 3.0,也即API level 11开始引入的,所以对于之前的版本,需要使用support library中的Fra ...
- Android的Fragment介绍
前言 fragment是从android3.0开始提出来的,用来支持大屏幕设备的ui设计.通过将activity划分为多个fragment,不仅提高了设计的灵活性,而且可以在程序运行时改变它们的特征, ...
- 《Android进阶》之第五篇 Fragment 的使用
http://blog.csdn.net/lmj623565791/article/details/37970961 1.Fragment的产生与介绍 Android运行在各种各样的设备中,有小屏幕的 ...
- 我的Android进阶之旅------>关于调用Webservice查询火车票时刻表的几个接口介绍
今天发现一个可以提供火车票时刻表查询的WebService,先记录下来以后如果写一个火车票时刻表查询的Android App的话就用的着.首先该WebService的的名字是TrainTimeWebS ...
- 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam
由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...
- [置顶] 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam
由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...
- 《Android进阶》之第六篇 Fragment 的使用2
最近通过学习,对fragment的使用有了新的认识. 一开始接触android的时候,很是受不了这个fragment,总感觉它把一个简单的事情搞复杂啦,所以每次新建工程的时候总是固执的选择empty ...
- Android之Fragment 基本介绍(转)
Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...
- 【Android进阶篇】Fragment的两种载入方式
一.概述 Fragment(碎片,片段)是在Android 3.0后才引入的,基本的目的是为了实如今大屏幕设备上的更加动态更加灵活的UI设计. 这是由于平板电脑的屏幕比手机大得多,所以屏幕上能够放很多 ...
随机推荐
- 【性能测试】性能测试总结<一>
目录: 一. 什么是软件性能 二.不同群体眼中的性能 三.性能测试类型 四.性能测试应用场景 五.性能测试基本概念 正文: 一. 什么是软件性能 定义:软件的性能是软件的一种非功能特性,它关注的不是软 ...
- 【Andorid开发框架学习】之Mina开发之客户端开发
昨天我们讲到了Mina的基本知识点.如果还有不懂得同学可以看一下我昨天的博客.http://www.cnblogs.com/getherBlog/p/3934927.html今天我着重来讲一下基于Mi ...
- Centos7安装Zabbix3.0
1.安装服务器端包 #rpm -ivh http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-release-3.0-1.el7.noarch. ...
- SVN在团队项目中的使用技巧:[2]Tag操作
SVN是Subversion的简称,是一个开放源代码的版本控制系统 本节讲述SVN使用中的TAG操作 文中若有错误或不足之处,欢迎留言指正 工具/原料 电脑 SVN 方法/步骤 1.认识SVN中T ...
- eclipse导入html、js、xml报错的问题
今天重新安装eclipse,在导入部分html.js.xml文件,报错,解决办法如下: eclipse->window->preferences->Team,点击validation ...
- ios8 ios7 tableview cell 分割线左对齐
ios8中左对齐代码 //加入如下代码 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cel ...
- SQL 中delete和truncate区别
1.前者按行删除,后者直接删除数据页 2.前者可带where删除部分,后者只能删除全表 3.前者在事务日志中记录每一行的记录,后者只记录页的释放 4.前者删除后,标识技术值不重置,后者重置 5.由fo ...
- solr环境搭建
介绍摘自百度百科:Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引:也可以通过 ...
- PLSQL_Oracle簇表和簇表管理Index clustered tables(案例)
2012-06-08 Created By BaoXinjian
- OAF_VO系列1 - Accelerator Keys
OAF_EO系列6 - Delete详解和实现(案例) (2014-06-16 08:37)