Hi,各位花粉们,上一节Android中最最常用—Fragment基础篇最详解,我们详细的介绍了 Fragment
的基本原理及使用、 Fragment
中的常用方法等。在这一节,将结合具体的使用场景,来更加全面的介绍 Fragment
的日常使用。
RadioButton
+ Fragment
在之前介绍的你不能错过的RadioButton实践一文中,我们详细介绍了 RadioButton
的使用,在示例:实现微信底部Tab效果中,只是实现了底部导航的效果切换,那怎么使导航上面的内容页面随着底部Tab的切换而改变呢?下面就结合 Fragment
实现这个效果。
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>
Fragment
,然后创建对应的4个布局(根据自己情况而定)。以下创建了4个示例 Fragment
:FragmentHome(首页)、FragmentDiscovery(发现)、FragmentContacts(通讯录)、FragmentMine(我的)。
Activity
中实例化各个 Fragment
和 RadioButton
和 RadioParent
的控件,设置好监听器。RadioButton
和 Fragment
,通过 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
,用户切换时隐藏。
ViewPager
+ Fragment
上面初步实现了一个APP的底部导航栏效果,但细心地读者可能会发现,微信的四个主页面是可以左右滑动切换的,而上面的效果只能是点击底部导航Tab进行切换。要实现左右页面滑动切换,就要使用我们接下来需要介绍的控件 ViewPager
了。
ViewPager
是 support v4
库中提供界面滑动的类,继承自 ViewGroup
。PagerAdapter
是 ViewPager
的适配器类,为 ViewPager
提供界面。但是一般来说,通常都会使用 PagerAdapter
的两个子类:FragmentPagerAdapter
和 FragmentStatePagerAdapter
作为 ViewPager
的适配器,他们的特点是界面是 Fragment
。
默认, ViewPager
会缓存当前页相邻的界面,比如当滑动到第2页时,会初始化第1页和第3页的界面(即 Fragment
对象,且生命周期函数运行到 onResume()
),可以通过 setOffscreenPageLimit(count)
设置离线缓存的界面个数。
FragmentPagerAdapter
和 FragmentStatePagerAdapter
需要重写的方法都一样,常见的重写方法如下:
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。FragmentPagerAdapter
和 FragmentStatePagerAdapter
的区别:
FragmentPagerAdapter
该类内的每一个生成的 Fragment
都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种。FragmentStatePagerAdapter
其内部不断重建和销毁,适合处理有很多页,并且数据动态性较大、占用内存较多的情况。修改原代码,新增 ViewPager
关联 RadioButton
和 Fragment
,步骤如下:
Activity
布局文件,替换 FrameLayout
为 ViewPager
。<?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>
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();
}
}
ViewPager
和 MyViewPagerAdapter
,并进行关联。//添加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);
RadioGroup
和 ViewPager
和监听,进行 RadioGroup
和 ViewPager
关联。//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);
}
}
});
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的一些常见使用场景,根据示例,可以变换多种使用形式,这就要求我们举一反三,根据具体业务、具体需求灵活运用。赶快在项目中练习使用吧!
如果你觉得本篇对你有所帮助,欢迎转载分享,标志出处即可,谢谢支持。