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

此文档参考了其它文档,现在也共享出来和大家分享,如有问题可以留言给我

最新文章

  1. Tip8:Unity中诸如 Awake() Start() Update()等函数的 执行顺序
  2. JavaScript事件大全
  3. java 版本安装
  4. PSP0表格二
  5. SQL Server 本地语言版本
  6. linux 查看cpu 内存 硬盘 文件夹大小
  7. crm使用soap更改下拉框的文本值
  8. GDB 多进程调试
  9. hdu 5590 ZYB&#39;s Biology
  10. Binders 与 Window Tokens(窗体令牌)
  11. Installing IIS 8.5 on Windows Server 2012 R2
  12. React入门实例
  13. CodeForces 581D Three Logos
  14. java学习——平台的安装与部署
  15. ini文件必须要全路径名啊
  16. jquery多种方式实现输入框input输入时的onput,onpropertychange,onchange触发事件及区别
  17. python程序的标准输入输出
  18. js 遍历 each() 方法
  19. Ubuntu通过ADB连接手机
  20. spring cloud实战与思考(三) 微服务之间通过fiegn上传一组文件(下)

热门文章

  1. objective-c 随便记记
  2. SSH_框架整合5--验证用户名是否可用
  3. Puppet Agent/Master HTTPS Communications
  4. worker_pool的例子
  5. 多用less命令,不会输入h查看对应的详细文档
  6. libcurl上传文件,添加自定义头
  7. MongoDB:Replica Set 之操作日志 Oplog
  8. [Android实例] Scroll原理-附ScrollView源码分析
  9. window下安装oracle数据库
  10. 深入研究java.lang.ThreadLocal类(转)