Android——探究碎片

1碎片是什么

碎片(Fragment) 是一种可以嵌入在活动当中的UI片段,能让程序更加合理和充分地利用大屏幕的空间,因而在平板应用十分广泛。

2碎片的使用方式

2.1 碎片的简单用法

写一个最简单的碎片示例,在一个活动当中添加两个碎片,并让这两个碎片平分活动空间 。
先创建一个平板模拟器,新建一个项目。
新建一个左侧碎片布局left_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button"
        android:text="Button"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_height="wrap_content" />


</LinearLayout>

然后新建右侧碎片布局right_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#00ff00"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/text_view"
        android:gravity="center_horizontal"
        android:text="this is right fragment"
        android:textSize="20sp"/>

</LinearLayout>

接着新建LeftFragment类,让它继承Fragment

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

这里仅仅重写了Fragment的onCreateView()的方法,然后在这个方法中通过LayoutInflater的inflate()方法将刚才定义的left_fragment布局动态加载进来。
用同样的方法再新建一个RightFragment

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

接下来修改activity_main.xml中的代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"/>
    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"/>

</LinearLayout>

这里使用了< fragment >标签在布局中添加碎片,需要注意的是这里需要通过android:name属性来显式指明要添加的碎片类名,注意,一定要把类的包名也加上。效果如下
在这里插入图片描述
两个碎片平分了整个活动的布局。

2.2动态加载碎片

碎片的强大之处在于可以在程序运行时动态的添加到活动中。根据具体情况来动态添加碎片,就可以将程序界面制定得更多样化。
在上一节的基础上,新建another_right_fragment

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#ffff00"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textSize="20sp"
        android:text="this is another right fragment"/>
</LinearLayout>

然后新建AnotherRightFragment作为另一个右侧碎片

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

在onCreateView()方法中加载了刚刚创建的another_right_fragment布局,这样就准备好了另一个碎片,然后将它动态地添加到活动当中,修改activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <fragment
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"/>
    <FrameLayout
        android:id="@+id/right_layout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1">
    </FrameLayout>

</LinearLayout>

现在右侧碎片替换成了一个FrameLayout,这是Android中最简单的一种布局,所有的控件默认都会摆放在布局的左上角,由于这里仅需要在布局里放一个碎片,不需要任何定位,因此非常适合使用FrameLayout。
然后在代码中向FrameLayout里添加内容,从而实现动态添加碎片的功能,修改MainActivity中的代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }
    @Override
    public void onClick(View view){
        switch(view.getId()){
            case R.id.button:
                replaceFragment(new AnotherRightFragment());
                break;
            default:
                break;
        }

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

}

可以看到,我们给左侧碎片中的按钮注册了一个点击事件,然后调用了replaceFragment()方法动态添加了RightFragment这个碎片当点击左侧碎片的按钮时,又会调用replaceFragment()方法将右侧碎片替换成AnotherRightFragment

动态添加碎片主要分为5步:
1.创建待添加的碎片实例
2.获取FragmentManger,在活动中可以通过直接调用getSupportFragmentManger()方法得到。
3.开启一个事务通过beginTransaction()开启
4.向容器内添加或替换碎片,一般使用replace()方法实现,需要传入容器的id待添加碎片的实例
5.提交事务,调用commit()方法来完成

2.3 在碎片中模拟返回栈

通过按钮点击添加了一个碎片之后,这是按下Back键就会直接退出程序,这里我们想模仿类似返回栈的效果,按下Back键返回上一个碎片,FragmentTransaction中提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中,修改MainActivity中的代码

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

提交事务前调用了FragmentTransaction的addToStack()方法,他可以接受一个名字用于描述返回栈的状态,一般传入null即可。

2.4碎片和活动之间的通信

为了方便碎片和活动之间通信,FragmentManger提供了一个类似于findViewById()的方法,专门用于从布局文件中获取碎片,代码如下

RightFragment rightFragment = (RightFragment) getSupportFragmentManager().findFeagmentById(R.id.right_fragment);

调用FragmentManager的findFragmentById()方法,可在活动中得到相应碎片的实例,然后就能轻松地调用碎片里的方法了。
在碎片中又该怎样调用活动里的方法**:每个碎片中都可以通过调用getActivity()方法得到和当前碎片相关联的活动**

MainActivity activity = (MainActivity) getActivity();

另外当碎片中需要使用Context对象时,也可以使用getActivity()方法,因为获取到的活动本身就是一个Context对象。

若想实现碎片与碎片之间的通信,首先在一个碎片中可得到与它关联的活动,然后再通过这个活动去获取到另一个碎片的实例,就实现了不同碎片的通信功能。

2.3 碎片的生命周期

每个活动在其生命周期内有四个状态,运行状态暂停状态停止状态销毁状态,类似的,每个碎片在其生命周期内也可能经历这几种状态,一些细小的地方有区别。
1.运行状态:当一个碎片是可见的,并且它所关联的活动正处于运行状态,该碎片也是运行状态。
2.暂停状态:一个活动进入暂停状态时(由于另一个未占满屏幕的活动被添加到了栈顶),与它相关联的可见碎片就会进入到暂停状态。
3.停止状态:当一个活动进入停止状态时,与它相关联的碎片就会进入到停止状态,或者通过调用FragmentTransaction的remove(),replace()方法将碎片从活动中移除,但如果在事务提交之前调用addToBackStack()方法,这时碎片也会进入到停止状态。总的来说,进入停止状态的碎片对于用户来说是完全不可见的,有可能会被系统回收。
4.销毁状态:碎片总是依附于活动而存在,因此当活动被销毁时,与他相关联的碎片就会进入到销毁状态。或者通过调用FragmentTransaction的remove(),replace()方法将碎片从活动中移除,但如果在事务提交之前没有调用addToBackStack()方法,这时碎片也会进入到销毁状态。

同样的Fragment类中也提供了一系列回调方法,以覆盖碎片生命周期的每个环节。其中,活动中有的回调方法,碎片中几乎都有,不过碎片提供了一些附加的回调方法。

  • onAttach() 当碎片和活动建立关联的时候
  • onCreateView() 当碎片创建视图(加载布局)时调用
  • onActivityCreated() 确保碎片相关联的活动一定已经创建完毕时调用
  • onDestroyView()当与碎片关联的视图被移除的时候调用。
  • onDetach()当碎片和活动解除关联的时候。
    在这里插入图片描述

2.4动态加载布局的技巧

2.4.1使用限定符

怎样才能在运行时通过判断程序应该时使用双页模式还是单页模式,需要借助限定符来实现。
举一个例子:修改activity_main.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"/>


</LinearLayout>

只留下一个左侧碎片,并让它充满整个布局,然后在res目录下新建layout-large文件夹,在这个文件夹下新建一个布局,也叫做activity_xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <fragment
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"/>
    <fragment
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="match_parent"
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"/>

</LinearLayout>

layout/activity_main.xml只包含了一个碎片,单页模式,layout-large/activity_main布局包含了两个碎片,双页模式。其中large是一个限定符,那些屏幕被认为是large的设备会自动加载layout-large文件夹下的布局,小屏幕设备会加载layout文件夹下的布局。然后将MainActivity中的replaceFragment()方法里的代码注释掉,重新运行
在这里插入图片描述
在这里插入图片描述

Android中一些常见的限定符
在这里插入图片描述
在这里插入图片描述

2.4.2使用最小宽度限定符

因为不知道large多大,希望更加灵活的为不同设备加载布局,不管他们是不是被系统认定为large,这时使用最小宽度限定符。
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备加载一个布局,小的加载另一个布局。

例子:在res目录下新建layout-sw600dp文件夹,在这个文件夹新建activity_main.xml布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <fragment
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"/>
    <fragment
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="match_parent"
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"/>

</LinearLayout>

当程序运行在屏幕大于600dp的设备上时,会加载layout-sw600dp/activity_main布局小于时,会加载默认布局。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值