说说如何使用 Android 的碎片(Fragment)

开发环境:Android 2.x

1 创建平板模拟器

在项目中点击 “shift + F9”,这时会弹出模拟器选择框,点击 Create New Virtual Device:

模拟器选择框

选择 Tablet,尽量选大屏的模拟器哟,因为这样看的清楚:


选择平板

一路 next,最后点击运行我们刚创建的平板模拟器:

平板模拟器

2 基本用法

我们在一个活动当中添加两个碎片,并让这两个碎片平分这个活动空间。

首先新建一个左侧碎片布局:

<?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">

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

这个布局非常简单,只放置了一个按钮,并让它水平居中显示。接着新建右侧碎片布局:

<?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="#00a000"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="我是右边的碎片"
        android:textSize="25sp"
        android:textColor="#ffffff"
        />

</LinearLayout>

这个布局把背景色设置为深绿色,并放置了一个 TextView 用于显示一段文本。

接着新建一个继承自 Fragment 的类。注意,这里会有两个不同包下的 Fragment 类供选择,一个是系统内置的 android.app.Fragment,一个是 support-v4 库中的 android.support.v4.app.Fragment。强烈建议使用 support-v4 库中的 Fragment,因为它可以让碎片在所有 Android 系统版本中保持功能一致哟!因为 appcomcat-v7 库会把 support-v4 库一起引入进来,所以我们不必在 gradle 中引入这个库。

LeftFragment :

public class LeftFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.left_fragment, container, false);
    }
}

这里仅仅是重写了 Fragment 的 onCreateView() 方法,然后在这个方法中通过 LayoutInflater 的 inflate()方法将刚刚定义的 fragment_left 布局动态加载进来而已。接着我们用同样的方法创建来 RightFragment 类:

public class RightFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.right_fragment, container, false);
    }
}

修改主活动类的布局文件:

<?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="horizontal">

    <fragment
        android:id="@+id/left_fragment"
        android:name="net.deniro.android.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        />


    <fragment
        android:id="@+id/right_fragment"
        android:name="net.deniro.android.fragmenttest.RightFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        />
</LinearLayout>

这里使用了 <fragment> 标签用于在布局中添加碎片,通过 android:name 属性来显式指明要添加的碎片类名,注意一 定要是类的全名哦O(∩_∩)O~

碎片示例

2 动态添加碎片

碎片真正的强大之处在于,它可以在程序运行时动态地被添加到活动当中。根据具体情况来动态地添加碎片,就可以实现程序界面的定制功能。

我们新建一个布局文件:

<?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"
    android:background="#ffff00"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textSize="20sp"
        android:text="我是另一个右碎片"
        />
</LinearLayout>

这个碎片只是把背景色改为黄色。然后再新建一个 Fragment:

public class AnotherRightFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.another_right_fragment, container, false);
    }
}

在主界面中加入一个 FrameLayout:

<?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="horizontal">

    <fragment
        android:id="@+id/left_fragment"
        android:name="net.deniro.android.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        />


   <FrameLayout
       android:id="@+id/right_layout"
       android:layout_width="0dp"
       android:layout_height="match_parent"
        android:layout_weight="1"
       ></FrameLayout>
</LinearLayout>

我们打算只放一个碎片,因为 FrameLayout 布局中的所有控件都会默认摆放在布局的左上角,所以这里很适合使用 FrameLayout 布局。

最后修改主活动中的代码:

public class MainActivity extends AppCompatActivity {

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

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               replace(new AnotherRightFragment());
            }
        });
    }

    private void replace(Fragment fragment) {
        FragmentManager manager=getSupportFragmentManager();
        FragmentTransaction transaction=manager.beginTransaction();
        transaction.replace(R.id.right_layout,fragment);
        transaction.commit();

    }
}

我们给左侧碎片中的按钮注册了一个点击事件,事件内部会调用 replace() 方法动态添加碎片。动态添加碎片分为 5 步:

  1. 创建待添加的碎片实例。
  2. 获取 FragmentManager,在活动中可以直接调用 getSupportFragmentManager()方法获取。
  3. 开启一个事务。
  4. 向容器内添加或替换碎片,一般使用 replace() 方法实现,需要传入容器的 id 和待添加或替换的碎片实例。
  5. 提交事务。
动态添加碎片

3 在碎片中模拟栈

上面,我们实现了向活动中动态添加碎片的功能,但通过点击按钮添加了一个碎片之后,按下 Back 键程序就会直接退出。如何才能够模拟 “返回栈” 的效果,让这个示例点击两次 Back 键才会退出程序呢?

FragmentTransaction 中有一个 addToBackStack() 方法,可以将一个事务添加到栈中,我们修改 Activity 中的代码:

private void replace(Fragment fragment) {
    FragmentManager manager=getSupportFragmentManager();
    FragmentTransaction transaction=manager.beginTransaction();
    transaction.replace(R.id.right_layout,fragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

4 碎片和活动之间的通信

为了方便碎片和活动之间进行通信,FragmentManager 提供了一个类似于 findViewById() 的方法,专用于从布局文件中获取碎片的实例:

//从布局文件中获取碎片实例
RightFragment rightFragment = (RightFragment) getSupportFragmentManager().findFragmentById(R.id.right_layout);

** 注意:要使用 getSupportFragmentManager() 来获取碎片管理器哦**

从碎片中也可以直接返回相关的活动:

//从碎片中调用活动
Activity activity = rightFragment.getActivity();

另外,如果需要在碎片中获取 Context 对象时,也可以直接调用 getActivity(),因为 Activity 本身就是 Context 对象啦O(∩_∩)O哈哈~

从活动中也可以再调用碎片实例:

 //从活动中再调用碎片实例
      +  ((AppCompatActivity) activity).getSupportFragmentManager().findFragmentById(R.id.right_layout);

这里记得向下转型为 AppCompatActivity 哦。

有了上面的方法,我们就能让碎片与碎片之间通信啦:

  1. 从 A 碎片中得到相关联的活动。
  2. 通过这个活动获取 B 碎片的实例。

A 碎片 → 关联活动 → B 碎片

是不是很清楚呀O(∩_∩)O~

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,520评论 25 707
  • 1. 引言   现如今移动设备的发展非常的迅速,手机和平板都非常的普及了。这两者的差距除了屏幕的大小以外,其他的差...
    忆念成风阅读 714评论 1 1
  • Fragment概述 Fragment是Activity中用户界面的一个行为或者说是一部分。主要是支持大屏幕上动态...
    wangling90阅读 11,522评论 5 76
  • 一大片向日葵花田,阳光灿烈而耀目。 他抚着画板,轻声道:“要向着阳光啊。”她轻眯着眼,看着他的微卷短发在光下泛着神...
    阿离夫阅读 416评论 0 4
  • 簿荷,在我们老家用客家话的来说的话是“碧迟”。碧迟的味道非常浓郁,手轻轻拂过叶子都能闻到手中明显的香味。但这碧迟...
    张啊_d719阅读 864评论 0 0