Android中最最常用—Fragment实战篇最详解

  • 2019 年 10 月 7 日
  • 笔记

前言

Hi,各位花粉们,上一节Android中最最常用—Fragment基础篇最详解,我们详细的介绍了 Fragment的基本原理及使用、 Fragment中的常用方法等。在这一节,将结合具体的使用场景,来更加全面的介绍 Fragment的日常使用。

示例一: RadioButton+ Fragment

在之前介绍的你不能错过的RadioButton实践一文中,我们详细介绍了 RadioButton的使用,在示例:实现微信底部Tab效果中,只是实现了底部导航的效果切换,那怎么使导航上面的内容页面随着底部Tab的切换而改变呢?下面就结合 Fragment实现这个效果。

1.修改原 Activity的主布局页面,新增 FrameLayout作为 Fragment的容器。
<?xml version="1.0" encoding="utf-8"?>  <androidx.constraintlayout.widget.ConstraintLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:context=".MyFragmentActivity">        <FrameLayout          android:id="@+id/container"          android:layout_width="match_parent"          android:layout_height="0dp"          app:layout_constraintBottom_toTopOf="@+id/radioGroup"          app:layout_constraintTop_toTopOf="parent" />        <RadioGroup          android:id="@+id/radioGroup"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:orientation="horizontal"          android:paddingTop="10dp"          android:paddingBottom="10dp"          app:layout_constraintBottom_toBottomOf="parent">            <RadioButton              android:id="@+id/rbHome"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:button="@null"              android:checked="true"              android:drawableTop="@drawable/tab_home_selector"              android:gravity="center_horizontal"              android:text="首页"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbDiscovery"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_discovery_selector"              android:gravity="center_horizontal"              android:text="发现"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbContacts"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_contacts_selector"              android:gravity="center_horizontal"              android:text="通讯录"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbMe"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_me_selector"              android:gravity="center_horizontal"              android:text="我"              android:textColor="@drawable/tab_text_selector" />      </RadioGroup>    </androidx.constraintlayout.widget.ConstraintLayout>
2.创建4个 Fragment,然后创建对应的4个布局(根据自己情况而定)。

以下创建了4个示例 Fragment:FragmentHome(首页)、FragmentDiscovery(发现)、FragmentContacts(通讯录)、FragmentMine(我的)。

3.在 Activity中实例化各个 FragmentRadioButtonRadioParent的控件,设置好监听器。
4.关联 RadioButtonFragment,通过 switchFragment()的方法,控制 Fragment的显示和隐藏。
public class MyFragmentActivity extends AppCompatActivity {        private RadioGroup rg;      private RadioButton mRbHome;      private RadioButton mRbDiscovery;      private RadioButton mRbContacts;      private RadioButton mRbMe;        private Fragment mFragment;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_my_fragment);            //初始化View          initView();            //初始化Fragment          initFragment();            //RadioGroup切换监听          rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {              @Override              public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {                  switch (checkedId) {                      case R.id.rbHome:                          switchFragment(FragmentHome.newInstance("首页Fragment"));                          break;                      case R.id.rbDiscovery:                          switchFragment(FragmentDiscovery.newInstance("发现Fragment"));                          break;                      case R.id.rbContacts:                          switchFragment(FragmentContacts.newInstance("通讯录Fragment"));                          break;                      case R.id.rbMe:                          switchFragment(FragmentMy.newInstance("我的Fragment"));                          break;                      default:                          break;                  }              }          });      }        /**       * 加载默认的Fragment       */      private void initFragment() {          mFragment = FragmentHome.newInstance("首页Fragment");          getSupportFragmentManager().beginTransaction()                  .add(R.id.container, mFragment).commit();      }        private void switchFragment(Fragment fragment) {          //判断当前显示的Fragment是不是切换的Fragment          if (mFragment != fragment) {              //判断切换的Fragment是否已经添加过              if (!fragment.isAdded()) {                  //如果没有,则先把当前的Fragment隐藏,把切换的Fragment添加上                  getSupportFragmentManager().beginTransaction().hide(mFragment)                          .add(R.id.container, fragment).commit();              } else {                  //如果已经添加过,则先把当前的Fragment隐藏,把切换的Fragment显示出来                  getSupportFragmentManager().beginTransaction()                          .hide(mFragment).show(fragment).commit();              }              mFragment = fragment;          }      }        /**       * 动态设置四个tab的样式       */      private void initView() {          rg = findViewById(R.id.radioGroup);          mRbHome = findViewById(R.id.rbHome);          mRbContacts = findViewById(R.id.rbContacts);          mRbDiscovery = findViewById(R.id.rbDiscovery);          mRbMe = findViewById(R.id.rbMe);            setStyle(R.drawable.tab_home_selector, mRbHome);          setStyle(R.drawable.tab_contacts_selector, mRbContacts);          setStyle(R.drawable.tab_discovery_selector, mRbDiscovery);          setStyle(R.drawable.tab_me_selector, mRbMe);      }        /**       * 动态设置每个tab的图片宽高以及文字间距       *       * @param selector RadioButton的样式选择器       * @param rb       RadioButton的样式选择器       */      private void setStyle(int selector, RadioButton rb) {          Drawable drawableHome = getResources().getDrawable(selector);          drawableHome.setBounds(0, 0, 80, 80);          rb.setCompoundDrawables(null, drawableHome, null, null);      }  }

switchFragment()的方法中,判断切换的 Fragment是否已经添加过,避免每一次切换 Fragment的时候都调用 add()或者 replace(),而是通过 hide()show(),减少频繁地创建新的实例。

mFragment:用于记录当前加载的 Fragment,用户切换时隐藏。

5.最后效果如下。

示例二: ViewPager+ Fragment

上面初步实现了一个APP的底部导航栏效果,但细心地读者可能会发现,微信的四个主页面是可以左右滑动切换的,而上面的效果只能是点击底部导航Tab进行切换。要实现左右页面滑动切换,就要使用我们接下来需要介绍的控件 ViewPager了。

ViewPagersupport v4库中提供界面滑动的类,继承自 ViewGroupPagerAdapterViewPager的适配器类,为 ViewPager提供界面。但是一般来说,通常都会使用 PagerAdapter的两个子类:FragmentPagerAdapterFragmentStatePagerAdapter作为 ViewPager的适配器,他们的特点是界面是 Fragment

默认, ViewPager会缓存当前页相邻的界面,比如当滑动到第2页时,会初始化第1页和第3页的界面(即 Fragment对象,且生命周期函数运行到 onResume()),可以通过 setOffscreenPageLimit(count)设置离线缓存的界面个数。

FragmentPagerAdapterFragmentStatePagerAdapter需要重写的方法都一样,常见的重写方法如下:

  • publicFragmentPagerAdapter(FragmentManagerfm):构造函数,参数为 FragmentManager。如果是嵌套 Fragment场景,子 PagerAdapter的参数传入 getChildFragmentManager()
  • FragmentgetItem(intposition):返回第position位置的 Fragment必须重写
  • intgetCount():返回 ViewPager的页数,必须重写
  • ObjectinstantiateItem(ViewGroupcontainer,intposition):container是 ViewPager对象,返回第position个位置的 Fragment
  • voiddestroyItem(ViewGroupcontainer,intposition,Objectobject):container是 ViewPager对象,object是 Fragment对象。
  • getItemPosition(Objectobject):object是 Fragment对象,如果返回POSITIONUNCHANGED,则表示当前 Fragment不刷新,如果返回POSITIONNONE,则表示当前Fragment需要调用 destroyItem()instantiateItem()进行销毁和重建。默认情况下返回POSITION_UNCHANGED。

FragmentPagerAdapterFragmentStatePagerAdapter区别

  • FragmentPagerAdapter该类内的每一个生成的 Fragment都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种。
  • FragmentStatePagerAdapter其内部不断重建和销毁,适合处理有很多页,并且数据动态性较大、占用内存较多的情况。

修改原代码,新增 ViewPager关联 RadioButtonFragment,步骤如下:

1.修改 Activity布局文件,替换 FrameLayoutViewPager
<?xml version="1.0" encoding="utf-8"?>  <androidx.constraintlayout.widget.ConstraintLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:context=".MyFragmentActivity">        <!--替换FrameLayout为ViewPager-->      <androidx.viewpager.widget.ViewPager          android:id="@+id/viewPager"          android:layout_width="match_parent"          android:layout_height="0dp"          app:layout_constraintBottom_toTopOf="@+id/radioGroup"          app:layout_constraintTop_toTopOf="parent" />        <RadioGroup          android:id="@+id/radioGroup"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:orientation="horizontal"          android:paddingTop="10dp"          android:paddingBottom="10dp"          app:layout_constraintBottom_toBottomOf="parent">            <RadioButton              android:id="@+id/rbHome"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:button="@null"              android:checked="true"              android:drawableTop="@drawable/tab_home_selector"              android:gravity="center_horizontal"              android:text="首页"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbDiscovery"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_discovery_selector"              android:gravity="center_horizontal"              android:text="发现"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbContacts"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_contacts_selector"              android:gravity="center_horizontal"              android:text="通讯录"              android:textColor="@drawable/tab_text_selector" />            <RadioButton              android:id="@+id/rbMe"              android:layout_width="0dp"              android:layout_height="wrap_content"              android:layout_weight="1"              android:background="@null"              android:button="@null"              android:drawableTop="@drawable/tab_me_selector"              android:gravity="center_horizontal"              android:text="我"              android:textColor="@drawable/tab_text_selector" />      </RadioGroup>  </androidx.constraintlayout.widget.ConstraintLayout>
2.新建 MyViewPagerAdapter,继承自 FragmentPagerAdapter
public class MyViewPagerAdapter extends FragmentPagerAdapter {        private List<Fragment> mFragments;        public MyViewPagerAdapter(FragmentManager fm, List<Fragment> mFragments) {          super(fm);          this.mFragments = mFragments;      }        @Override      public Fragment getItem(int i) {          return mFragments.get(i);      }        @Override      public int getCount() {          return mFragments == null ? 0 : mFragments.size();      }  }
3.初始化 ViewPagerMyViewPagerAdapter,并进行关联。
//添加Fragment到集合中  List<Fragment> mFragmentList = new ArrayList<>();  mFragmentList.add(FragmentHome.newInstance("首页Fragment"));  mFragmentList.add(FragmentDiscovery.newInstance("发现Fragment"));  mFragmentList.add(FragmentContacts.newInstance("通讯录Fragment"));  mFragmentList.add(FragmentMy.newInstance("我的Fragment"));    //关联ViewPager与Adapter  MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager(), mFragmentList);  mViewPager.setAdapter(myViewPagerAdapter);
4.设置 RadioGroupViewPager和监听,进行 RadioGroupViewPager关联。
//RadioGroup切换监听 关联ViewPager相关页面  mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {      @Override      public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {          switch (checkedId) {              case R.id.rbHome:                  mViewPager.setCurrentItem(0);                  break;              case R.id.rbDiscovery:                  mViewPager.setCurrentItem(1);                  break;              case R.id.rbContacts:                  mViewPager.setCurrentItem(2);                  break;              case R.id.rbMe:                  mViewPager.setCurrentItem(3);                  break;              default:                  break;          }      }  });    //ViewPager滑动监听 关联相关RadioButton  mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {      @Override      public void onPageSelected(int position) {          if (position == 0) {              mRbHome.setChecked(true);          } else if (position == 1) {              mRbDiscovery.setChecked(true);          } else if (position == 2) {              mRbContacts.setChecked(true);          } else if (position == 3) {              mRbMe.setChecked(true);          }      }  });
5. Activity 完整代码及效果如下。
public class MyFragmentActivity extends AppCompatActivity {        private RadioGroup mRadioGroup;      private RadioButton mRbHome;      private RadioButton mRbDiscovery;      private RadioButton mRbContacts;      private RadioButton mRbMe;      private ViewPager mViewPager;        private MyViewPagerAdapter myViewPagerAdapter;      private List<Fragment> mFragmentList;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_my_fragment);            initView();            //添加Fragment到集合中          mFragmentList = new ArrayList<>();          mFragmentList.add(FragmentHome.newInstance("首页Fragment"));          mFragmentList.add(FragmentDiscovery.newInstance("发现Fragment"));          mFragmentList.add(FragmentContacts.newInstance("通讯录Fragment"));          mFragmentList.add(FragmentMy.newInstance("我的Fragment"));            //关联ViewPager与Adapter          myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager(), mFragmentList);          mViewPager.setAdapter(myViewPagerAdapter);            //默认选中首页          mViewPager.setCurrentItem(0);          mRbHome.setChecked(true);            //RadioGroup切换监听 关联ViewPager相关页面          mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {              @Override              public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {                  switch (checkedId) {                      case R.id.rbHome:                          mViewPager.setCurrentItem(0);                          break;                      case R.id.rbDiscovery:                          mViewPager.setCurrentItem(1);                          break;                      case R.id.rbContacts:                          mViewPager.setCurrentItem(2);                          break;                      case R.id.rbMe:                          mViewPager.setCurrentItem(3);                          break;                      default:                          break;                  }              }          });            //ViewPager滑动监听 关联相关RadioButton          mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {              @Override              public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {                }                @Override              public void onPageSelected(int position) {                  if (position == 0) {                      mRbHome.setChecked(true);                  } else if (position == 1) {                      mRbDiscovery.setChecked(true);                  } else if (position == 2) {                      mRbContacts.setChecked(true);                  } else if (position == 3) {                      mRbMe.setChecked(true);                  }              }                @Override              public void onPageScrollStateChanged(int state) {                }          });      }        /**       * 动态设置四个tab的样式       */      private void initView() {          mRadioGroup = findViewById(R.id.radioGroup);          mRbHome = findViewById(R.id.rbHome);          mRbContacts = findViewById(R.id.rbContacts);          mRbDiscovery = findViewById(R.id.rbDiscovery);          mRbMe = findViewById(R.id.rbMe);          mViewPager = findViewById(R.id.viewPager);            setStyle(R.drawable.tab_home_selector, mRbHome);          setStyle(R.drawable.tab_contacts_selector, mRbContacts);          setStyle(R.drawable.tab_discovery_selector, mRbDiscovery);          setStyle(R.drawable.tab_me_selector, mRbMe);      }        /**       * 动态设置每个tab的图片宽高以及文字间距       *       * @param selector RadioButton的样式选择器       * @param rb       RadioButton的样式选择器       */      private void setStyle(int selector, RadioButton rb) {          //定义底部标签图片大小和位置          Drawable drawableHome = getResources().getDrawable(selector);          //当这个图片被绘制时,给他绑定一个矩形 ltrb规定这个矩形          drawableHome.setBounds(0, 0, 80, 80);          //设置图片在文字的哪个方向          rb.setCompoundDrawables(null, drawableHome, null, null);      }  }

结语

以上就是Fragment的一些常见使用场景,根据示例,可以变换多种使用形式,这就要求我们举一反三,根据具体业务、具体需求灵活运用。赶快在项目中练习使用吧!

如果你觉得本篇对你有所帮助,欢迎转载分享,标志出处即可,谢谢支持。