Android底部导航框架(解决fragment界面重现,getActivity空指针)

android底部导航框架可以说是目前最常用的框架,看似非常简单的框架如果搭建不好后期会出现各种意想不到问题;

比如我前面两篇写的每次点击底部图标fragment之间会来回替换,这样肯定不实用;这个demo使用add(),hide(),show()代替replace()

再者当打开app之后按home键退出,浏览其他app当内存重启的时候再次打开我们的app会出现四个fragment重现的问题;

经过我们伟大的测试不断的努力下,进入首页立马退出,然后再进入...如此反复操作会出现getActivity()报空指针;

想要更深入的了解fragment推荐给大家一篇文章:http://www.jianshu.com/p/d9143a92ad94

如果大家手里没有成熟的框架,可以直接到文章底部下载源码,可以直接使用;


整体的大布局是一个线性布局,按照权重8:1分配fragment的父布局和下面的底部导航栏

<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:orientation="vertical"
    tools:context="www.relative.com.relativeframe.MainActivity">

    <!--存放fragment-->
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_above="@+id/tab_layout"
        android:layout_weight="8"></FrameLayout>

    <!--底部导航-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:gravity="bottom"
        android:layout_weight="1">

        <include
            android:id="@+id/tab_layout"
            layout="@layout/view_main_tab" />

    </LinearLayout>
</LinearLayout>

底部导航也是一个线性布局,我们重点看下“进货单”,其他三个也一样,只不过没有显示消息的TextView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:layout_alignParentBottom="true"
    android:orientation="horizontal"
    android:background="#27282c">

    <!--首页-->
    <RelativeLayout/>
  
    <!--商品-->
    <RelativeLayout />

    <!--进货单-->
    <RelativeLayout
        android:id="@+id/shopping_cart_page"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginTop="4dp"
        android:layout_weight="1">
        <RadioButton
            android:id="@+id/shopping_cart_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@null"
            android:button="@null"
            android:clickable="false"
            android:drawablePadding="5dp"
            android:drawableTop="@drawable/selector_tab_stock_list"
            android:gravity="center"
            android:text="进货单"
            android:textColor="@drawable/tab_text_selector"
            android:textSize="10sp" />
        <TextView
            android:id="@+id/shopping_cart_num"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:layout_alignRight="@id/shopping_cart_button"
            android:layout_alignTop="@id/shopping_cart_button"
            android:layout_marginTop="-6dp"
            android:layout_gravity="right"
            android:background="@drawable/msg_num_shape"
            android:clickable="false"
            android:gravity="center"
            android:text="99+"
            android:textColor="@color/white"
            android:textSize="8sp" />
    </RelativeLayout>

    <!--会员-->
    <RelativeLayout />

</LinearLayout>
布局写法很多,但是万变不离其宗,几乎都差不多;

其实逻辑也比较简单:

第一:初始化view和fragment(将fragment保存到一个集合)

第二:显示选中的Fragment

第三:处理RadioButton的点击事件,当点击的时候显示对应的Fragment并且改变RadioButton的状态

第四:重写onSaveInstanceState()方法,注销super...

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

        fragmentManager = getSupportFragmentManager();
        initView();

        // 显示选中的 Fragment
        showFragment();

    }

    //初始化view和fragment
    private void initView() {

        fragmentList.add(new HomeFragment());
        fragmentList.add(new GoodsFragment());
        fragmentList.add(new ShoppingFragment());
        fragmentList.add(new UserFragment());

        ...
    }

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

        switch (v.getId()) {

            case R.id.homepage://首页
                currentIndex = 0;
                changeState(true, false, false, false);
                break;

            case R.id.goods_page://商品
                currentIndex = 1;
                changeState(false, true, false, false);
                break;

            case R.id.shopping_cart_page://进货单
                currentIndex = 2;
                changeState(false, false, true, false);
                break;

            case R.id.user_page://会员
                currentIndex = 3;
                changeState(false, false, false, true);
                break;

        }

        showFragment();

    }

    //改变RadioButton的状态
    private void changeState(boolean homeB, boolean goodsB, boolean shopB, boolean userB) {
        btnHome.setChecked(homeB);
        btnGoods.setChecked(goodsB);
        btnShopCart.setChecked(shopB);
        btnUserVip.setChecked(userB);
    }



    // 显示选中的 Fragment
    private void showFragment() {

        Fragment currentFragment = fragmentList.get(currentIndex);

        FragmentTransaction ft = fragmentManager.beginTransaction();

        //如果当前的fragment没有添加,添加当前的fragment
        if(!currentFragment.isAdded()){
            /**
             * 把fragment添加到MainActivity中
             * 第一个参数:fragment添加的位置;(必须是布局容器,一般是一个framelayout)
             * 第二个参数:要添加的fragment对象
             */
            ft.add(R.id.fragment_container, currentFragment);
        }

        for(int x=0;x<fragmentList.size();x++){
            if(fragmentList.get(x)!=currentFragment){
                //隐藏不需要显示的Fragment,仅仅是设为不可见,并不会销毁
                ft.hide(fragmentList.get(x));
            }else {
                ft.show(fragmentList.get(x));
            }
        }
        ft.commit();

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //super.onSaveInstanceState(outState);
    }

最后注销的super.onSaveInstanceState()方法是系统的方法,在内存重启的时候会调用,作用就是在内存重启的时候不让系统做任何操作,这样就不会出现重叠现象;

解决getActivity()空指针,需要创建一个Fragment的基类(BaseFragment),然后在BaseFragment中:

public class BaseFragment extends Fragment {

    private Activity mActivity;

    @Override
    /**
     * 当Fragment与Activity发生关联时调用
     *
     * 在Fragment基类里设置一个Activity mActivity的全局变量,在onAttach(Activity activity)里赋值,
     * 使用mActivity代替getActivity(),保证Fragment即使在onDetach后,仍持有Activity的引用
     */
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mActivity = (Activity) context;
    }

}


点击打开链接免费下载源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值