Fragment基础

概念

Fragment英文原意是碎片,片段的意思,为了应对android的碎片化,Fragmnet的概念在Android3.0中被引入进来,主要目的是用在大屏幕设备上--例如平板电脑上,支持更加动态和灵活的UI设计。平板电脑的屏幕比手机大得多,有更多的空间来放更多的UI组件,并且这些组件之间会产生更多的交互。
Fragment在应用中应当是一个模块化和可重用的组件,因为Fragment定义了自己的布局,以及通过使用它自己的生命周期回调方法定义了它自己的行为,你可以将Fragment包含到多个Activity中,一个Activiy也可以包含多个Fragment。

下面这张图可以帮助理解Fragment的概念:

知识概要

  1. Fragment可以作为Activity界面的一部分组成出现
  2. 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用
  3. 在Activity运行过程中,可以添加,移除或替换Fragment
  4. Fragment可以响应自己的输入时间,并且有自己的生命周期,其生命周期受宿主Activity的生命周期影响

Fragment的使用

创建Fragment

静态创建

静态创建需要在在布局文件中声明Fragment,需要特别注意的是Fragment中的android:name属性指定了在layout中实例化的Fragment类 ,同时必须要标识Fragment。

标识Fragment的方法:

android:id 属性提供一个唯一的ID
android:tag 属性提供一个唯一的字符串

** 创建方法:**

  1. 在布局文件中声明一个fragment组件,name指向3中创建的类对象
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.w2.test.MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="button1"
        android:text="Button1"
        android:textSize="18sp"

        />
    <!--声明一个fragment-->
    <fragment
        android:id="@+id/fragment"
        android:name="com.w2.test.MyFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

2.创建fragment布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这是一个静态加载的Fragment"
        android:id="@+id/textView"
        android:layout_gravity="center_horizontal"
        android:textSize="20sp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change"
        android:id="@+id/button"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

3.创建MyFragment类继承Fragment对象,重写onCreateView方法返回布局文件的View

public class MyFragment extends Fragment{
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        /**
         * resource:Fragment需要加载的布局文件
         * root:加载layout的父ViewGroup
         * attactToRoot:false,不返回父ViewGroup
         */
        View v = inflater.inflate(R.layout.fragment,container,false);
        View view = inflater.inflate(R.layout.fragment, container, false);
        final TextView text=(TextView) v.findViewById(R.id.textView);
        Button button=(Button) v.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                text.setText("测试成功");
            }
        });
        return v;
    }
}

动态创建

在Java代码中撰写代码将Fragment添加到Activity layout中。

add():添加一个Fragment,指定要添加的Fragment和插入的View

与此类似的还有remove(),repalce()等

诸如上述对Fragment进行添加,移除,替换以及执行其他动作,提交给Activity的每一套变化被称为一个事物,处理这类事物需要Fragment Manager,通过FragmentManager开启事务。

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();

每一个事务都是同时执行一套变化,可以在一个事务中设置所要执行的操作,然后提交给Activity,之后必须要调用commit方法。

如果允许用户通过按下BACK按键返回到前一个Fragment状态,调用commit之前可以加入addToBackStack()方法。

FragmentManager fragmentManager = getFragmentManager(); //获取FragmentManager
FragmentTransaction beginTransaction = fragmentManager.beginTransaction(); //开启事务
beginTransaction.add(R.id.frame, fragment2); //添加Fragment,参数1containerViewId传入Fragment的父布局,参数2fragment穿入Fragment的实例化对象
beginTransaction.addToBackStack(null); //增加回退功能,回到上一个事务状态
beginTransaction.commit(); //提交事务

Fragment的生命周期

  • Fragment生命周期图


  • 与Activity生命周期对比


每个方法的回调条件:

  • onCreateView()
    每次创建都会绘制Fragment的View组件时回调该方法
    Fragment第一次绘制它的用户界面的时候,系统会调用此方法,为了绘制Fragment的UI,此方法必须返回一个View,如果不显示UI,返回null即可。

  • onAttach
    当Fragment被添加到Activity时候会回调这个方法,并且只调用一次

  • onCreate
    创建Fragment时会回调,只会调用一次

  • onActivityCreated
    当Fragment所在的Activty启动完成后调用

  • onStart
    启动Fragment

  • onResume
    恢复Fragment时会被回调,调用onStart()方法后面一定会调用onResume()方法

  • onPause
    暂停Fragment

  • onStop
    停止Fragment

  • onDestroyView
    销毁Fragment所包含的View组件时

  • onDestroy
    销毁Fragment时会被回调

  • onDetach
    Fragment从Activity中删除时会回调该方法,并且这个方法只会调用一次

Fragment与Activity互相通信

Activity向Fragment传递数据

在Activity中创建Bundle数据包,并调用Fragment的setArgument(Bundle bundle)方法。这种方式是在加载Fragment之前传递数据的。

Activity:

//动态加载Fragment的同时传递数据
String text = editText.getText().toString(); //获取要传递的数据
Bundle bundle = new Bundle();
if (text!=null){
    bundle.putString("msg",text);
}
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle);
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.frame,fragment,"MyFragment");
transaction.addToBackStack(null);
transaction.commit();

Fragment:

//获取数据并令TextView显示
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment,container,false);
        TextView text=(TextView) v.findViewById(R.id.textView);
        text.setText(getArguments().get("msg").toString());
        return v;
    }

** 注意,这里取得传递过来的数据用的是@getArgument方法,@setArgument中传入的bundle只是一个数据类型,与savedInstanceState这个参数没有关系。我之前用savedInstanceState.getString()获取数据一直错误,很久都找不到错误。**

Fragment向Activity传递数据

需要在Fragment中定义回调接口,再让包含该Fragment的Activity实现该回调接口。这样Fragment可以调用该回调方法传数据给Activity。

  • 在Fragment中定义接口,并在接口中定义传递数据的抽象方法
    public interface MyListener{
        public void send(String code);
    }
  • 令Activity实现定义的接口,并重写定义的方法
public class MainActivity extends AppCompatActivity implements MyFragment.MyListener
...
@Override
public void send(String code) {

}
  • 在Fragment中将创建接口对象并指向Activity,最后传入String
MyListener listener;
@Override
public void onAttach(Activity activity) { //不一定非要在onAttach中
    listener = (MyListener) activity;
    super.onAttach(activity);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment,container,false);
    TextView text=(TextView) v.findViewById(R.id.textView);
    text.setText(getArguments().get("msg").toString());
    listener.send("这是发送给Activity的数据");//也不一定非在onCreateView中
    return v;
}
  • 在Activity中接收数据
@Override
public void send(String code) {
    editText.setText(code);
}

Activity向静态加载Fragment传递数据

  • 首先按静态加载方式创建Fragment

  • 在Fragment的创建数据用来接收传来的数据,设置get和set方法

    public String a;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }
  • 在Activity通过Fragment.findFragmentById找到Fragment,通过set方法传递数据
FragmentManager fragmentManager = getFragmentManager();
MyFragment fragment = (MyFragment) fragmentManager.findFragmentById(R.id.fragment);
fragment.setA(text);
  • 最后在Fragment中通过get方法接收数据
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,373评论 25 707
  • Fragment要点 1、Fragment作为Activity界面的一部分组成出现 2、可以在一个Activity...
    玉圣阅读 1,219评论 0 16
  • 引言 A Fragment represents a behavior or a portion of user ...
    伍零一阅读 820评论 4 16
  • 一个轮回的对视:一个是羡慕,一个是好奇,我曾是你,你终会是我。人生,如此而已...... 孩子怎样成长,老人就怎样...
    田田126阅读 285评论 1 1
  • 在百花睡眼迷蒙时, 你花枝花枝招展的最灿烂, 那时的你是何等的红光满面, 那时的你如一个热恋中的小女孩,...
    嘻嘻向阳露阅读 130评论 0 0