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 介绍和使用 (一)的更多相关文章

  1. Android 进阶 Fragment 介绍和使用 (二)

    管理fragment 因为FragmentManager的API是在Android 3.0,也即API level 11开始引入的,所以对于之前的版本,需要使用support library中的Fra ...

  2. Android的Fragment介绍

    前言 fragment是从android3.0开始提出来的,用来支持大屏幕设备的ui设计.通过将activity划分为多个fragment,不仅提高了设计的灵活性,而且可以在程序运行时改变它们的特征, ...

  3. 《Android进阶》之第五篇 Fragment 的使用

    http://blog.csdn.net/lmj623565791/article/details/37970961 1.Fragment的产生与介绍 Android运行在各种各样的设备中,有小屏幕的 ...

  4. 我的Android进阶之旅------>关于调用Webservice查询火车票时刻表的几个接口介绍

    今天发现一个可以提供火车票时刻表查询的WebService,先记录下来以后如果写一个火车票时刻表查询的Android App的话就用的着.首先该WebService的的名字是TrainTimeWebS ...

  5. 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

    由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...

  6. [置顶] 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

    由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...

  7. 《Android进阶》之第六篇 Fragment 的使用2

    最近通过学习,对fragment的使用有了新的认识. 一开始接触android的时候,很是受不了这个fragment,总感觉它把一个简单的事情搞复杂啦,所以每次新建工程的时候总是固执的选择empty ...

  8. Android之Fragment 基本介绍(转)

    Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...

  9. 【Android进阶篇】Fragment的两种载入方式

    一.概述 Fragment(碎片,片段)是在Android 3.0后才引入的,基本的目的是为了实如今大屏幕设备上的更加动态更加灵活的UI设计. 这是由于平板电脑的屏幕比手机大得多,所以屏幕上能够放很多 ...

随机推荐

  1. Debian安装记录

    Fedora着实让我伤心透了.前天和昨天搞了整整两天Fedora 20的安装,午睡也没有,晚上就睡了四个小时不到,几乎尝试了所有Fedora 20的桌面版本,全部出问题了!就因为我的笔记本显卡是ATI ...

  2. JAVA解析各种编码密钥对(DER、PEM、openssh公钥)

    一.DER编码密钥对 先说下DER编码,是因为JCE本身是支持DER编码密钥对的解析的,可以参见PKCS8EncodedKeySpec和X509EncodedKeySpec. DER编码是ASN.1编 ...

  3. HttpWebRequest 注意

    使用HttpWebRequest 一定要保证GetRequestStream和GetResponse对象关闭,否则容易造成连接处于CLOSE_WAIT状态 using (Stream stream = ...

  4. [tty与uart]2.tty和uart的函数调用流程

    以下是在include/uapi/linux/tty.h中定义了现有的线规号,如果需要定义新的,则需要在后面添加新的 /* line disciplines */ #define N_TTY 0 #d ...

  5. MongoDB:Replica Set 之操作日志 Oplog

    转载地址:http://francs3.blog.163.com/blog/static/4057672720121133328120/ 之前的blog  学习了 MongoDB 主从搭建,以及节点管 ...

  6. 【Android】源码external/目录中在编译过程中生成的文件列表

    => external/eyes-free:   accessibilityvalidator.jar (host,share) => external/mesa3d:   libMesa ...

  7. Maven exclusion

    <dependency><exclusions> <exclusion> <groupId>xx</group> <artifactI ...

  8. PO_PO系列 - 安全文件管控管理分析(案例)

    2014-07-01 Created By BaoXinjian

  9. alpha融合

    //alpha融合 //作者:sandy //时间:2015-10-6 //将一只狗的头像融合在蜗牛头上 #include <cv.h> #include <highgui.h> ...

  10. 错误记录 git pull

    在安装open-falcon的nodata组件,更新库的时候,git pull 报错: You are not currently on a branch, so I cannot use any'b ...