Fragment的优雅实践并杂谈细节

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/KING_GUOGUO/article/details/84255578

虽然Fragment设计的初衷是为了大屏幕的平板设备,但走着走着它目前已经广泛应用于我们的手机设备上了。比如下面我们常见的设计就可以使用fragment实现,先来个图片三连:

program.png

Read.png

manageMoney.png

对于这个设计有很多种方式实现,比如可以使用TabLayout+Fragment,不过我想快速且优雅的实现,所以最终借助了一个第三方库实现下面的布局Table,采用了BottomNavigation+Fragment的方式。

BottomNavigation的GitHub地址:
https://github.com/armcha/LuseenBottomNavigation

也可以直接

implementation 'com.github.armcha:LuseenBottomNavigation:1.8.2'

那么下面就开始本文的重点内容了

一、主页面布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

  <FrameLayout
      android:id="@+id/fr_content"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
  </FrameLayout>

<com.luseen.luseenbottomnavigation.BottomNavigation.BottomNavigationView
    android:id="@+id/bnv_item"
    android:layout_width="match_parent"
    android:layout_height="30dp"
    app:bnv_colored_background="false"
    android:layout_alignParentBottom="true">
</com.luseen.luseenbottomnavigation.BottomNavigation.BottomNavigationView>

</RelativeLayout>

主页面的布局很简洁,FrameLayout就是展示fragment内容的地方,下面的BottomNavigationView就是底部导航栏控件。

二、实现底部导航栏布局效果

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.fr_content)
    FrameLayout frContent;
    @BindView(R.id.bnv_item)
    BottomNavigationView mBottomView;
    //...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        BottomNavigationItem bottomNavigationItem=new BottomNavigationItem("首页",
                ContextCompat.getColor(this,R.color.mainPager),R.drawable.loudspeaker);
        BottomNavigationItem bottomNavigationItem1=new BottomNavigationItem("编程",
                ContextCompat.getColor(this,R.color.programCode),R.drawable.program);
        BottomNavigationItem bottomNavigationItem2=new BottomNavigationItem("读书",
                ContextCompat.getColor(this,R.color.readPager),R.drawable.book);
        BottomNavigationItem bottomNavigationItem3=new BottomNavigationItem("理财",
                ContextCompat.getColor(this,R.color.manageMoneyPager),R.drawable.money);
        mBottomView.addTab(bottomNavigationItem);
        mBottomView.addTab(bottomNavigationItem1);
        mBottomView.addTab(bottomNavigationItem2);
        mBottomView.addTab(bottomNavigationItem3);
        //...
        }

代码很清晰,创建多个底部的每个item实例,再将其加入到view中。

这里我做了一下怪[啊哈哈],使用了ButterKnife来获取控件,你可以不用,按照最原始的方式即可。到这里已经完成了一小半了,够快吧…

三、准备一个Fragment

这里我们创建了4个fragment,分别是首页、编程、读书和理财。我就拿理财来举例了(最近迷上了理财这个东西),其他三个都是一样的,或许这就是传说中的举一反三吧。

ManageMoneyFragment.class

public class ManageMoneyFragment extends Fragment {
    private static final String TAG = "ManageMoneyFragment";

    @Override
    public void onAttach(Context context) {
        Log.d(TAG, "onAttach: ");
        super.onAttach(context);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView: ");
        return inflater.inflate(R.layout.manage_money_fragment,null);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onViewCreated: ");
        super.onViewCreated(view, savedInstanceState);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onActivityCreated: ");
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: ");
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "onStart: ");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "onResume: ");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.d(TAG, "onPause: ");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.d(TAG, "onStop: ");
        super.onStop();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        Log.d(TAG, "onDestroyView: ");
        super.onDestroyView();
    }

    @Override
    public void onDetach() {
        Log.d(TAG, "onDetach: ");
        super.onDetach();
    }
}

什么鬼,写了这么长一串感觉啥也没干啊,这不都是activity的生命周期方法嘛。哈哈,准确的这些都是Fragment的生命周期方法,写这些是为了下面小谈一些它的生命周期。

其实Fragment可以算Android里的第五大组件了,之前,有人把View作为第五大组件,但是由于相对于四大组件来说它没有生命周期,所以从这个角度来说,Fragment更适合称为第五大组件。

创建一个fragment到用户能看到的状态经历了以下的生命周期
创建fragment.png

同样销毁一个fragment会经历如下生命周期
销毁fragment.png

或许这张图看起来会更清晰明了一点
fragment生命周期.png

相比于Activity,它的生命周期方法多了几个,比如它最开始的方法走的是onAttach,销毁的最后一步是onDetach方法,它们是一对方法因为fragment是需要依附Activity存在的,所以就有了这样的两个方法。

好,可以回来了,在上面代码中和我们的页面view直接相关的是 onCreateView方法,用inflater.inflate方法把fragment的页面布局填充进去就好了

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView: ");
        return inflater.inflate(R.layout.manage_money_fragment,null);
    }

随便写了一个简单的布局

R.layout.manage_money_fragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/frag_manage_money"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="35sp"
      android:layout_centerInParent="true"
      android:text="  在别人贪婪的时候,我们要恐惧;
  在别人恐惧的时候,我们要贪婪;"/>
</RelativeLayout>

四、依附到Activity中

这是最后一步也是最关键的一步,fragment是需要依附到Activity中的。

在底部的导航栏view中,是有个点击方法的,通过这个点击方法我们对每个item进行选择,从而切换到相应的fragment

public class MainActivity extends AppCompatActivity {
    //当前的fragment
    private Fragment mCurrFragment=new Fragment();
    //理财的fragment
    private ManageMoneyFragment mManageMoneyFragment=new ManageMoneyFragment();
    //编程的fragment
    private ProgramFragment mProgramFragment=new ProgramFragment();
    //阅读的fragment
    private ReadFragment mReadFragment=new ReadFragment();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //....省略上面已展示的

        //点击底部按钮选择对应的fragment
        mBottomView.setOnBottomNavigationItemClickListener(new OnBottomNavigationItemClickListener() {
            @Override
            public void onNavigationItemClick(int index) {
                switch (index){
                    case 0:
                        skipToHome();
                        break;
                    case 1:
                       skipToProgram();
                        break;
                    case 2:
                        skipToRead();
                        break;
                    case 3:
                        skipToManage();
                        break;
                    default:
                        break;
                }
            }
        });
    }

    //跳转到理财fragment
    private void skipToManage() {
       switchFragment(mManageMoneyFragment);
    }
    
    //.....

因为在添加导航栏的item时,它的内部实现是ArrayList,所以只需要判断它的index就可以获取对应的item了。

选择完后,进行fragment的展示。这里我们使用的hide和show的方式,对于没有添加到ArrayList的,需要先添加再展示,对于已经添加过的我们直接展示就好了,注意在展示之前要将当前展示的先隐藏。

对于隐藏这样的方式就有个好处,我们不需要重复创建它的实例,节省了不必要消耗的性能和用户的流量。

  private void switchFragment(Fragment targetFragment){
        FragmentTransaction fragmentTransaction=getSupportFragmentManager().beginTransaction();
         //隐藏目前的fragment,展示目标fragment
        if(!targetFragment.isAdded()){
            fragmentTransaction.hide(mCurrFragment)
             .add(R.id.fr_content,targetFragment,targetFragment.getClass().getName())
                    .commit();
        }else {
            fragmentTransaction.hide(mCurrFragment)
                    .show(targetFragment)
                    .commit();
        }
        mCurrFragment=targetFragment;
    }

到这里,就实现了笔者最开始的素质三连图的最后一张了。对于其他两张图我们只需要再添加两个fragment,再依附到Activity中就ok了.整个过程还是很优雅的哈[蜜汁微笑QAQ]

猜你喜欢

转载自blog.csdn.net/KING_GUOGUO/article/details/84255578