虽然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; }
作者:树獭非懒
链接:https://www.jianshu.com/p/6ea2b8b10b62