A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张老师 黑马粉丝团   /  2016-11-25 16:55  /  1890 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 就业部_安卓组 于 2016-12-6 16:05 编辑

Fragment 的使用
       Fragment 的使用分为两种,分别是静态和动态,静态的使用是最简单的一种方式,就是将 Fragment 当做普通的一种控件,直接写在 Activity 的布局里面就可以了。而动态的使用相对而言比较复杂,下面会一一介绍。

静态的使用
       静态的使用 Fragment ,包括两个步骤:
       1.继承 Fragment,重写 onCreateView 并填充一个 view 用于显示 Fragment 的布局
       2.在 Activity 中声明此 Fragment
       多说无益,直接写代码展示,在此我要实现这样的界面,上面是一个内容布局,下面是一个底部布局。如果用 Activity 来写,无非就是两个 TextView 就可以了,上面一个下面一个。但是我要用 Fragment 来实现就不一样了,代码如下:
       首先我先定义上面的内容布局文件 fragment_content.xml:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#333333"
        android:gravity="center"
        android:text="我是上面的内容 Fragment"
        android:textColor="#ffffff"
        android:textSize="20sp" />

</LinearLayout>

然后快速的书写内容布局的 Fragment

[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Created by mesmerize on 2016/11/17.
 * 内容 Fragment
 */

public class ContentFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_content, null);

        TextView tv_content = (TextView) view.findViewById(R.id.tv_content);

        tv_content.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(getActivity(), "你点击了上面的内容 Fragment ", Toast.LENGTH_SHORT).show();
            }
        });

        return view;
    }

}
       这段代码就是在做第一步,我创建了一个 ContentFragment 并继承自 Fragment,重写 onCreateView 方法,然后填充 fragment_content.xml 这个布局文件作为该 Fragment 的 view。
       同时我查找出了当前布局文件里面的那个 TextView 控件并给该控件设置了一个点击事件,点击这个 TextView 会弹出来一个 Toast。
       接下来我们按照上述的代码形式快速的写出底层的 Fragment。

fragment_bottom.xml
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_bottom"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="我是底部的 Fragment"
        android:textSize="20sp" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher" />
</LinearLayout>

这个 xml 文件,上面是一个 TextView 文本,下面是一个 ImageView 显示一张小机器人的图片。
该 xml 布局文件对应的 Fragment 代码如下:
BottomFragment
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Created by mesmerize on 2016/11/17.
 * 底部的 Fragment
 */

public class BottomFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_bottom, null);

        TextView tv_content = (TextView) view.findViewById(R.id.tv_bottom);

        tv_content.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(getActivity(), "你点击了底部的内容 Fragment ", Toast.LENGTH_SHORT).show();
            }
        });

        return view;
    }
}

       跟内容的 ContentFragment 代码差不多,只是填充的布局文件不一样,弹出的 Toast 内容不一样。
       以上做的就是我们所说的第一步,接下来做第二步,在 Activity 布局文件中声明。首先我们书写 Activity 的 xml 布局:
activity_main.xml
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/fragment_content"
        android:name="com.mesmerize.helloworld.ContentFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"></fragment>


    <fragment
        android:id="@+id/fragment_bottom"
        android:name="com.mesmerize.helloworld.BottomFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"></fragment>

</LinearLayout>

       布局很简单,其中用到了 weight 权重这个属性,它的意思就是所占的比例,比如在该布局里面,我写了两个weight,那这两个 weight 加一起就是 2 ,这是总的数。而每一个 fragment 都占了 1,也就是占总数的 1/2 。因此它们两个 fragment 平均分配了这个手机屏幕的大小,也就是上下各占一半。
MainActivity
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

至此,就大功告成了,速度运行一下,看看结果。





尝试一下点击上面的 “我是上面的内容 Fragment”这句话,看看会不会弹出来一句话。





没有问题。那再点一下下面的试试。





也没有问题!
       可以看到,我们的弹出 Toast 以及查找控件等控件的事件处理的代码都由各自的 Fragment 去处理了,而我们的 Activity 什么都不用写,仅仅显示一下就行了。这就是我们常说的“高内聚低耦合”,赶紧去试试吧!

动态的使用

       通过上面的演示相信现在你已经学会了静态使用的方式了,但是这仅仅只是 Fragment 最简单的功能而已。接下来我将介绍如何动态的添加、更新以及删除 Fragment。
       平时我们所使用 app 比如 QQ、微信、微博、淘宝、京东,都是类似这样的结构:



       也就是下面几个按钮,然后中间是内容区域,点击下面的按钮,可以动态替换上面的内容区域,而今天我们就来写一个类似这种架构的小小的 Demo


       效果图如下:







       很简单的需求,就是下面几个文字,上面是内容区域,点击下面的文字,动态替换上面的文本区域里面的文字内容,这怎么来做呢?
       其实,这一块就要涉及到 Fragment 的动态替换了,话不多说了,直接上代码。
       首先是 activity_main.xml 文件,根据效果图,我们分析,上面的内容区域可以用一个 FrameLayout 来填充,待会可以动态的用不同的 Fragment 来替换即可,而下面用简单的四个 TextView 就行了。我们快速的编写代码:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="40dp"></FrameLayout>

    <LinearLayout
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal">

        <TextView
            android:gravity="center"
            android:id="@+id/tv_chat"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="聊天"
            android:textColor="#288CFB"
            android:textSize="16sp" />

        <TextView
            android:gravity="center"
            android:id="@+id/tv_address"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="通讯录"
            android:textColor="#288CFB"
            android:textSize="16sp" />

        <TextView
            android:gravity="center"
            android:id="@+id/tv_find"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="发现"
            android:textColor="#288CFB"
            android:textSize="16sp" />


        <TextView
            android:gravity="center"
            android:id="@+id/tv_me"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="我"
            android:textColor="#288CFB"
            android:textSize="16sp" />
    </LinearLayout>
</RelativeLayout>

中间一个 FrameLayout ,下面四个 TextView , 显示效果如下:

       可以看到下面有四个选项,我们的需求是每次点击一个选项的时候将上面的 FrameLayout 内容更换,而在这里,我们的 FrameLayout 由 Fragment 来填充,因此,我们首先要创建好四个 Fragment ,待会点击的时候动态的去替换不同的 Fragment。
       所以在这里,我们快速创建四个 Fragment 以及他们的布局文件。
       首先是聊天 (ChatFragment):
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * 聊天 Fragment
 */

public class ChatFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_chat, null);
        return view;
    }
}

fragment_chat.xml 如下:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff0000"
    android:orientation="vertical">

    <TextView
        android:text="我是聊天Fragment"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

显示效果如下:


       可以看到是一个红色背景的文本内容。这是聊天的 Fragment。
接下来是通讯录(AddressFragment)的代码:
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * 通讯录 Fragment
 */

public class AddressFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_address, null);
        return view;
    }
}
fragment_address.xml 如下:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00f0f0"
    android:orientation="vertical">

    <TextView
        android:text="我是通讯录Fragment"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

效果如下:


接下来同样的方式创建另外两个 Fragment,发现(FindFragment)以及我(MeFragment):
FindFragment:
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * 发现 Fragment
 */

public class FindFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_find, null);
        return view;
    }
}

fragment_find.xml
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff00ff"
    android:orientation="vertical">

    <TextView
        android:text="我是发现Fragment"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

效果:


MeFragment:
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * 我 Fragment
 */

public class MeFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_me, null);
        return view;
    }
}
fragment_me.xml
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0f0f0f"
    android:orientation="vertical">

    <TextView
        android:text="我是我Fragment"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
效果:


       到这里,四个 Fragment 已经创建完成,那接下来开始在 MainActivity 里面填充,并且处理一些业务逻辑,比如点击下面的选项,动态切换上面的 FrameLayout 内容。注释我都加在代码里面,代码如下:
[Java] 纯文本查看 复制代码
package com.mesmerize.helloworld;

import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tv_chat;
    private TextView tv_address;
    private TextView tv_find;
    private TextView tv_me;
    private ChatFragment mChatFragment;
    private AddressFragment mAddressFragment;
    private FindFragment mFindFragment;
    private MeFragment mMeFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initListener();
        initDefaultFragment();
    }

    /**
     * 初始化 View 控件
     */
    private void initView(){

        tv_chat = (TextView) findViewById(R.id.tv_chat);
        tv_address = (TextView) findViewById(R.id.tv_address);
        tv_find = (TextView) findViewById(R.id.tv_find);
        tv_me = (TextView) findViewById(R.id.tv_me);

    }

    /**
     * 初始化 事件监听事件
     */
    private void initListener(){

        tv_chat.setOnClickListener(this);
        tv_address.setOnClickListener(this);
        tv_find.setOnClickListener(this);
        tv_me.setOnClickListener(this);
    }

    /**
     * 初始化 默认显示的 Fragment
     */
    private void initDefaultFragment(){

        FragmentManager fm = getFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        transaction.replace(R.id.fl_content, new ChatFragment());
        transaction.commit();
    }

    /**
     * 点击事件
     */
    @Override
    public void onClick(View v) {

        FragmentManager fm = getFragmentManager();

        // 开启事务
        FragmentTransaction transaction = fm.beginTransaction();

        switch (v.getId()){

            case R.id.tv_chat:

                if (mChatFragment == null) {

                    mChatFragment = new ChatFragment();
                }

                // 替换
                transaction.replace(R.id.fl_content, mChatFragment);

                break;
            case R.id.tv_address:

                if (mAddressFragment == null) {

                    mAddressFragment = new AddressFragment();
                }

                // 替换
                transaction.replace(R.id.fl_content, mAddressFragment);
                break;
            case R.id.tv_find:

                if (mFindFragment == null) {

                    mFindFragment = new FindFragment();
                }

                // 替换
                transaction.replace(R.id.fl_content, mFindFragment);
                break;
            case R.id.tv_me:

                if (mMeFragment == null) {

                    mMeFragment = new MeFragment();
                }

                // 替换
                transaction.replace(R.id.fl_content, mMeFragment);
                break;
        }

        // 提交事务
        transaction.commit();
    }
}
       在 onCreate 里面调用了 initView、initListener、initDefaultFragment,分别是初始化 View 控件、设置点击事件以及初始化默认显示的 Fragment,在这里我们初始化的 Fragment 是聊天 Fragment,即 ChatFragment。可以看到我们需要开启一个事务,通过 FragmentManager 对象得到,然后调用 replace() 方法进行替换,参数1的意思为被替换的文本内容,参数2是用谁来替换,最后调用 commit() 方法提交,到此,一个动态替换 Fragment 的逻辑完成了。
       然后我们在 onClick 点击事件里面进行业务逻辑处理,根据点击的控件 id 进行 switch 判断,并动态替换每一个 Fragment 。
       以上就是一个简单的逻辑处理。
       在这里需要注意 FragmentManager,如果是使用 Android 3.0 以下的版本,则需要引入 v4 的包,然后 Activity 继承 FragmentActivity,并且要通过        getSupportFragmentManager 的形式来获得 FragmentManager。这是版本向下兼容。

Fragment 常用 API

       getFragmentManager() :获取 FragmentManager ,但在 v4 中,需要用 getSupportFragmentManager
       fm.beginTransaction() :开启一个事务,可以通过事务做很多操作
       transaction.add() :在 Activity 中添加一个 Fragment
       transaction.remove() :移除一个 Fragment
       transaction.replace() :使用一个 Fragment 替换当前正在显示的 Fragment,可以理解为 remove 和 add 的结合
       transaction.hide() :隐藏当前的 Fragment,不会销毁,就像控件设置 visibile 为 invisibile 一样,Fragment 只是不可见
       transaction.show() :显示隐藏的 Fragment
       transaction.commit() :提交事务,也就是你之前调用了那些,现在要提交以生效。
       以上,是操作 Fragment 的基本方式,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。如果你经常使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
      下节讲 Fragment 与 Activity 和 Fragment 之间的通信、Fragment 回退栈的一些用法。Fragment 终极解析(三)






      
Android 人事+技术总贴
       Android 基础篇总贴
       Android 进阶篇总贴
       Android 讨论区

       以上言论,如有错误或者表达不准确或者有纰漏的地方还请指正,同时欢迎大家在评论区留言给予一定的建议,我会根据大家的意见进行相应的改正,谢谢各位!







2 个回复

倒序浏览
新人路过 顶一个!
回复 使用道具 举报

谢谢支持
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马