伴职创作「banzhi.cc」书客创作[ibooker.cc]Android开发经验谈

【Android】android.app.Fragment实现选

2018-03-01  本文已影响98人  吾非言

作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc

本文选自书客创作平台第117篇文章。阅读原文

书客创作

前言:

Fragment是Android3.0后引入的一个新的API,它出现的初衷是为了适应大屏幕的平板电脑, 当然现在它仍然是平板APP UI设计的宠儿,而且我们普通手机开发也会加入这个Fragment, 我们可以把它看成一个小型的Activity,又称Activity片段!想想,如果一个很大的界面,我们就一个布局,写起界面来会有多麻烦,而且如果组件多的话是管理起来也很麻烦!而使用Fragment我们可以把屏幕划分成几块,然后进行分组,进行一个模块化的管理!从而可以更加方便的在运行过程中动态地更新Activity的用户界面!另外Fragment并不能单独使用,它需要嵌套在Activity中使用,尽管它拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响,比如Activity被destory销毁了,它也会跟着销毁!

Fragment简介

Fragment生命周期图

上图是Fragment的生命周期图,从该图中可以看到Fragment拥有跟Activity相似的生命周期,例如都有onCreate,onStart,onStop等过程。当然它也有自己独特的过程例如onCreateView,onActivityCreated等。官方文档说创建Fragment时至少需要实现三个方法:onCreate,onCreateView,OnPause。实际上真正需要重写的方法只有onCreateView一个,因为该方法是给Fragment提供视图的,所以重写该方法必不可少。

Fragment该如何使用?

本小节就android.app.Fragment实现选项卡功能来说明Fragment的一些用法。

基本思想:android.app.Fragment只能结合Activity使用,在使用上其实可以把它当成Activity中的一个视图控件。说的简单一点就是在一个Activity中需要几个布局界面,就添加几个Fragment来呈现和管理。例如:要实现一个带有三个选项的选项卡:

一、布局

首先是Activity的布局,Activity需要显示选项卡界面和内容界面两个部分,这里的内容区由FrameLayout进行包裹,具体呈现内容交由Fragment来实现:

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <--内容区-->
        <FrameLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" >
        </FrameLayout>

        <--底部菜单栏-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#F5F5F5" >

            <RelativeLayout
                android:id="@+id/main_layout"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:orientation="vertical" >

                    <ImageView
                        android:id="@+id/main_image"
                        android:layout_width="50dp"
                        android:layout_height="30dp"
                        android:layout_gravity="center_horizontal"
                        android:contentDescription="@string/desc"
                        android:src="@drawable/main_tab1" />

                    <TextView
                        android:id="@+id/main_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:text="@string/main"
                        android:textColor="#929598"
                        android:textSize="15sp" />
                </LinearLayout>
            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/navigation_layout"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:orientation="vertical" >

                    <ImageView
                        android:id="@+id/navigation_image"
                        android:layout_width="50dp"
                        android:layout_height="30dp"
                        android:layout_gravity="center_horizontal"
                        android:contentDescription="@string/desc"
                        android:src="@drawable/navigation_tab2" />

                    <TextView
                        android:id="@+id/navigation_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:text="@string/navigation"
                        android:textColor="#929598"
                        android:textSize="15sp" />
                </LinearLayout>
            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/more_layout"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:orientation="vertical" >

                    <ImageView
                        android:id="@+id/more_image"
                        android:layout_width="50dp"
                        android:layout_height="30dp"
                        android:layout_gravity="center_horizontal"
                        android:src="@drawable/more_tab2" />

                    <TextView
                        android:id="@+id/more_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:text="@string/more"
                        android:textColor="#929598"
                        android:textSize="15sp" />
                </LinearLayout>
            </RelativeLayout>
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

二、Fragment加载布局文件

在Activity的布局文件中,内容区是由FrameLayout进行包裹,具体呈现内容布局是由Fragment来实现,那么Fragment是如何实现一个界面布局呢?假如这里有一个布局文件fragment_main.xml,那么实现该布局文件代码如下:

public class Main  extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
        View contactsLayout = inflater.inflate(R.layout.fragment_main, container, false);
        return contactsLayout;
    }
}

从上面可以看出页面不是一个Activity,而是一个Fragment。实现布局的加载是通过onCreateView()这个方法、通过LayoutInflater来获取页面view、false指的是添加非子视图、如果是true的话,就是添加子视图的意思。

三、最后,Fragment实现选项切换

在说明Fragment实现选项切换之前,首先要知道与FragmentTransaction相关的几个重要的方法。

// Fragment管理类
FragmentManager fragmentManager = getFragmentManager();
// 开启一个Fragment事务
FragmentTransaction transaction = fragmentManager.beginTransaction();

FragmentTransaction是Fragment的事务类,也是最直接操作Fragment的类。

transaction.add(int containerViewId, Fragment fragment);

add是用来添加一个Fragment到事务当中。

transaction.show(Fragment fragment);

show方法是用来展示Fragment。

 transaction.commit();

提交Fragment事务。

transaction.hide(Fragment fragment);

hide方法是隐藏Fragment,与show方法相对。

下面看一下Activity具体怎么实现页面的跳转:

public class MainActivity extends Activity implements OnClickListener {
    /**
    * 用于展示主页的Fragment
    */
    private Main mainFragment;
    /**
    * 用于展示导航的Fragment
    */
    private Navigation navigationFragment;
    /**
    * 用于展示更多的Fragment
    */
    private More moreFragment;
    /**
    * 主页界面布局
    */
    private View mainLayout;
    /**
    * 导航界面布局
    */
    private View navigationLayout;
    /**
    * 更多界面布局
    */
    private View moreLayout;
    /**
    * 在Tab布局上显示主页图标的控件
    */
    private ImageView mainImage;
    /**
    * 在Tab布局上显示导航图标的控件
    */
    private ImageView navigationImage;
    /**
    * 在Tab布局上显示更多图标的控件
    */
    private ImageView moreImage;
    /**
    * 在Tab布局上显示主页标题的控件
    */
    private TextView mainText;
    /**
    * 在Tab布局上显示导航标题的控件
    */
    private TextView navigationText;
    /**
    * 在Tab布局上显示更多标题的控件
    */
    private TextView moreText;
    /**
    * 用于对Fragment进行管理
    */
    private FragmentManager fragmentManager;

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

    // 初始化布局元素
    initViews();
    fragmentManager = getFragmentManager();
    // 第一次启动时选中第0个tab
    setTabSelection(0);
}

/**
* 在这里获取到每个需要用到的控件的实例,并给它们设置好必要的点击事件。
*/
private void initViews() {
    mainLayout = findViewById(R.id.main_layout);
    navigationLayout = findViewById(R.id.navigation_layout);
    moreLayout = findViewById(R.id.more_layout);

    mainImage = (ImageView) findViewById(R.id.main_image);
    navigationImage = (ImageView) findViewById(R.id.navigation_image);
    moreImage = (ImageView) findViewById(R.id.more_image);

    mainText = (TextView) findViewById(R.id.main_text);
    navigationText = (TextView) findViewById(R.id.navigation_text);
    moreText = (TextView) findViewById(R.id.more_text);

    mainLayout.setOnClickListener(this);
    navigationLayout.setOnClickListener(this);
    moreLayout.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.main_layout:
            // 当点击了主页tab时,选中第1个tab
            setTabSelection(0);
        break;
        case R.id.navigation_layout:
            // 当点击了导航tab时,选中第2个tab
            setTabSelection(1);
        break;
        case R.id.more_layout:
            // 当点击了更多tab时,选中第3个tab
            setTabSelection(2);
        break;
        default:
        break;
    }
}

/**
* 根据传入的index参数来设置选中的tab页。
*
* @param index 每个tab页对应的下标。0表示主页,1表示导航,2表示更多
*/
private void setTabSelection(int index) {
    // 每次选中之前先清楚掉上次的选中状态
    clearSelection();
    // 开启一个Fragment事务
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    // 先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况
    hideFragments(transaction);
    switch (index) {
        case 0:
        // 当点击了主页tab时,改变控件的图片和文字颜色
        mainImage.setImageResource(R.drawable.main_tab1);
        mainText.setTextColor(Color.parseColor("#0079FF"));
        if (mainFragment == null) {
            // 如果MessageFragment为空,则创建一个并添加到界面上
            mainFragment = new Main();
            transaction.add(R.id.content, mainFragment);
        } else {
            // 如果mainFragment不为空,则直接将它显示出来
            transaction.show(mainFragment);
        }
        break;
        case 1:
            // 当点击了导航tab时,改变控件的图片和文字颜色
            navigationImage.setImageResource(R.drawable.navigation_tab1);
            navigationText.setTextColor(Color.BLUE);
            if (navigationFragment == null) {
                // 如果navigationFragment为空,则创建一个并添加到界面上
                navigationFragment = new Navigation();
                transaction.add(R.id.content, navigationFragment);
            } else {
                // 如果navigationFragment不为空,则直接将它显示出来
                transaction.show(navigationFragment);
            }
            break;
            case 2:
                // 当点击了更多tab时,改变控件的图片和文字颜色
                moreImage.setImageResource(R.drawable.more_tab1);
                moreText.setTextColor(Color.BLUE);
                if (moreFragment == null) {
                    // 如果moreFragment为空,则创建一个并添加到界面上
                    moreFragment = new More();
                    transaction.add(R.id.content, moreFragment);
                } else {
                    // 如果moreFragment不为空,则直接将它显示出来
                    transaction.show(moreFragment);
                }
            break;
        }
        transaction.commit();
    }

    /**
    * 清除掉所有的选中状态。
    */
    private void clearSelection() {
        mainImage.setImageResource(R.drawable.main_tab2);
        mainText.setTextColor(Color.parseColor("#929598"));
        navigationImage.setImageResource(R.drawable.navigation_tab2);
        navigationText.setTextColor(Color.parseColor("#929598"));
        moreImage.setImageResource(R.drawable.more_tab2);
        moreText.setTextColor(Color.parseColor("#929598"));
    }

    /**
    * 将所有的Fragment都置为隐藏状态。
    *
    * @param transaction 用于对Fragment执行操作的事务
    */
    private void hideFragments(FragmentTransaction transaction) {
        if (mainFragment != null) {
            transaction.hide(mainFragment);
        }
        if (navigationFragment != null) {
            transaction.hide(navigationFragment);
        }
        if (moreFragment != null) {
            transaction.hide(moreFragment);
        }
    }
}

在本案例中一共提供了三个Fragment,分别是Main(mainFragment)、Navigation(navigationFragment)、More(moreFragment),这三个Fragment是虚构对象,具体代码未给出,这里只是用来说Activity内如何操作Fragment。实际上通过以上代码可以看出Fragment实现选项切换是通过FragmentTransaction来实现的,即由核心方法setTabSelection来实现。

阅读原文


微信公众号:书客创作
上一篇下一篇

猜你喜欢

热点阅读