Fraction的封装
一、前言
上篇文章介绍了Fraction,如果你还不知道如何使用Fraction,可以阅读Fraction的使用和生命周期这篇文章。
((FractionAbility) getAbility()).getFractionManager()
.startFractionScheduler()
.add(ResourceTable.Id_stack, new HomeFraction(), "home_fraction")
.submit();
在上篇文章中主要是使用上面的代码来将Fraction添加带AbilitySlice里面。请注意,之前只用到了一个Fraction,在实际开发中,肯定会有很多Fraction,那么有多少个Fraction,上面的代码就需要写多少次,这些都是重复的代码,遇到重复代码,就需要对其进行封装,封装后,上面的那段代码就不需要外界来写了。
二、效果图
三、封装
- 定义BaseFraction类
BaseFraction是个抽象类,子类需要重写getUIContent方法和initComponent方法,getUIContent方法用于获取布局文件的id,initComponent方法用于子类初始化组件。在onComponentAttached方法中调用scatter.parse(getUIContent(), container, false)将布局文件转换成组件对象,并赋值给mComponent,然后调用initComponent方法,最后将mComponent返回。
BaseFraction类暂时这样,如果大家觉得还有其它的代码可以添加带BaseFraction类中,可以自行添加。
/**
* fraction父类
*
* @author 裴云飞
* @date 2020/12/30
*/
public abstract class BaseFraction extends Fraction {
protected Component mComponent;
/**
* 获取布局文件的id
*
* @return 布局文件的id
*/
public abstract int getUIContent();
/**
* 初始化组件
*/
public abstract void initComponent();
@Override
protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
// 将布局文件转换成组件对象
mComponent = scatter.parse(getUIContent(), container, false);
// 初始化组件
initComponent();
return mComponent;
}
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
}
@Override
protected void onActive() {
super.onActive();
}
@Override
protected void onForeground(Intent intent) {
super.onForeground(intent);
}
@Override
protected void onInactive() {
super.onInactive();
}
@Override
protected void onStop() {
super.onStop();
}
/**
* 获取string.json文件中定义的字符串
*
* @param resId
* @return
*/
public String getString(int resId) {
try {
return getFractionAbility().getResourceManager().getElement(resId).getString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取color.json文件中定义颜色值
*
* @param colorId
* @return
*/
public int getColor(int colorId) {
try {
return getFractionAbility().getResourceManager().getElement(colorId).getColor();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
- 子类继承BaseFraction
子类在getUIContent方法返回自己的布局文件id,在initComponent方法里面初始化组件。
后续的fraction都需要继承BaseFraction。
public class CategoryFraction extends BaseFraction {
@Override
public int getUIContent() {
return ResourceTable.Layout_fraction_category;
}
@Override
public void initComponent() {
}
}
四、Fraction配合底部导航栏
1、在鸿蒙系统—打造通用的底部导航栏这篇文章中,我们封装了一个通用的底部导航栏,当时并没有使用Fraction,这次就使用Fraction。之前的底部导航栏总共有5个条目,每个条目都需要创建一个Fraction,并且继承BaseFraction,当点击某个条目,需要先将之前显示的Fraction隐藏掉,然后显示新的Fraction。比如,当前显示的是首页的Fraction,当点击收藏后,就需要先隐藏首页的Fraction,然后显示收藏的Fraction。
2、创建BarComponentProvider,这个是适配器类,也是个抽象类,子类需要重写getPage和getCount方法,getPage方法用于创建Fraction对象,getCount方法用于返回fraction的总数。
3、在构造方法里面让外界将FractionManager对象传递过来。
4、在createPageInContainer里面调用mFractionManager.startFractionScheduler开启事务,如果当前的fraction不为空,就隐藏当前的fraction,然后根据标签从FractionManager里面获取fraction,如果获取的fraction不为空,那就显示出来。如果获取的fraction为空,调用getPage方法创建fraction,将创建好的fraction添加到fractionScheduler,最后提交事务。
5、PlainArray是鸿蒙提供的一个集合,用于存储以整型作为键、以任何对象作为值的数据结构,PlainArray节省了内存,使用二分搜索查找元素。getPage方法用于创建对象,由于子类是通过反射创建fraction对象的,反射创建对象要比直接new一个对象更耗性能,所以使用缓存。首先从缓存里面查找,如果能查找到直接返回,否则让子类来创建对象,并将创建好的对象存入缓存。
public abstract class BarComponentProvider {
/**
* 当前的fraction
*/
protected Fraction mCurFraction;
/**
* fraction管理器
*/
protected FractionManager mFractionManager;
private PlainArray<Fraction> mFractionPlainArray;
public BarComponentProvider(FractionManager fractionManager) {
mFractionManager = fractionManager;
mFractionPlainArray = new PlainArray<>();
}
/**
* 创建fraction,并对fraction进行管理
*
* @param container
* @param position
*/
public void createPageInContainer(ComponentContainer container, int position) {
// 开启事务
FractionScheduler fractionScheduler = mFractionManager.startFractionScheduler();
if (mCurFraction != null) {
// 当前的fraction不为空,就隐藏
fractionScheduler.hide(mCurFraction);
}
String tag = container.getId() + ":" + position;
Fraction fraction;
// 根据标签从FractionManager里面获取fraction
Optional<Fraction> fractionOptional = mFractionManager.getFractionByTag(tag);
if (fractionOptional.isPresent()) {
fraction = fractionOptional.get();
// 获取的fraction不为空,显示出来
fractionScheduler.show(fraction);
} else {
// 获取的fraction为空,创建fraction
fraction = getPage(position);
// 将fraction添加到fractionScheduler
fractionScheduler.add(container.getId(), fraction, tag);
}
mCurFraction = fraction;
// 提交事务
fractionScheduler.submit();
}
/**
* 根据位置创建fraction对象
*
* @param position 位置
* @return fraction对象
*/
public Fraction getPage(int position) {
// 从缓存获取fraction对象
Optional<Fraction> fractionOptional = mFractionPlainArray.get(position);
if (fractionOptional.isPresent()) {
// 存在,直接返回
return fractionOptional.get();
}
// 不存在fraction对象,则让子类通过反射创建fraction对象
Fraction fraction = getFraction(position);
// 将创建好点的对象添加到缓存
mFractionPlainArray.put(position, fraction);
return fraction;
}
public abstract Fraction getFraction(int position);
/**
* fragment的总数
*
* @return fragment的总数
*/
public abstract int getCount();
/**
* 获取当前的fraction
*
* @return 当前的fraction
*/
public Fraction getCurrentFraction() {
return mCurFraction;
}
}
5、子类继承BarComponentProvider,集合里面就是底部导航栏中每个条目的数据,
public class BottomBarComponentProvider extends BarComponentProvider {
private List<BottomBarInfo<?>> mInfoList;
public BottomBarComponentProvider(List<BottomBarInfo<?>> infoList, FractionManager fractionManager) {
super(fractionManager);
mInfoList = infoList;
}
@Override
public Fraction getPage(int position) {
try {
return mInfoList.get(position).fraction.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public int getCount() {
return mInfoList.size();
}
}
6、在Fraction的使用和生命周期这篇文章中,我们是在布局文件中添加了一个栈布局。这次创建FractionBarComponent类,继承栈布局。setProvider方法用于设置适配器,这个适配器就是上面创建BarComponentProvider。setCurrentItem用于设置点前要显示的fraction,如果没有设置适配器,什么都不干。如果传递过来的位置与当前位置不相等,那就创建fraction。点击底部导航栏的时候,就会调用setCurrentItem方法
public class FractionBarComponent extends StackLayout {
private BarComponentProvider mProvider;
private int currentPosition;
public FractionBarComponent(Context context) {
this(context, null);
}
public FractionBarComponent(Context context, AttrSet attrSet) {
this(context, attrSet, "");
}
public FractionBarComponent(Context context, AttrSet attrSet, String styleName) {
super(context, attrSet, styleName);
}
/**
* 设置适配器
*
* @param provider
*/
public void setProvider(BarComponentProvider provider) {
if (mProvider != null || provider == null) {
return;
}
currentPosition = -1;
mProvider = provider;
}
/**
* 设置点前要显示的fraction
*
* @param position
*/
public void setCurrentItem(int position) {
if (position < 0 || position >= mProvider.getCount()) {
return;
}
if (currentPosition != position) {
currentPosition = position;
mProvider.createPageInContainer(this, position);
}
}
public int getCurrentItem() {
return currentPosition;
}
public Fraction getCurrentFraction() {
if (mProvider == null) {
return null;
}
return mProvider.getCurrentFraction();
}
}
8、在布局文件中使用,外层就是底部导航栏,底部导航栏里面就是一个栈布局
<?xml version="1.0" encoding="utf-8"?>
<com.pyf.ui.bar.bottom.BottomNavigationBar
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:id="$+id:bottom_navigation_bar"
ohos:orientation="vertical"
ohos:width="match_parent">
<com.pyf.common.bar.FractionBarComponent
ohos:height="match_parent"
ohos:id="$+id:fraction_bar_component"
ohos:width="match_parent"/>
</com.pyf.ui.bar.bottom.BottomNavigationBar>
9、在代码使用,最关键的代码就是当点击底部导航栏的时候,调用setCurrentItem方法显示fraction,该方法内部会先隐藏之前的fraction,然后显示新的fraction。
private void initBottom() {
tabBottomLayout = (BottomNavigationBar) mAbilitySliceProvider.findComponentById(ResourceTable.Id_bottom_navigation_bar);
bottomInfoList = new ArrayList<>();
// 获取string.json文件中定义的字符串
String home = mAbilitySliceProvider.getString(ResourceTable.String_home);
String favorite = mAbilitySliceProvider.getString(ResourceTable.String_favorite);
String category = mAbilitySliceProvider.getString(ResourceTable.String_category);
String find = mAbilitySliceProvider.getString(ResourceTable.String_find);
String profile = mAbilitySliceProvider.getString(ResourceTable.String_profile);
// 首页
BottomBarInfo<Integer> homeInfo = new BottomBarInfo<>(home,
ResourceTable.Media_home_normal,
ResourceTable.Media_home_selected,
defaultColor, tintColor);
homeInfo.fraction = HomeFraction.class;
// 收藏
BottomBarInfo<Integer> favoriteInfo = new BottomBarInfo<>(favorite,
ResourceTable.Media_favorite_normal,
ResourceTable.Media_favorite_selected,
defaultColor, tintColor);
favoriteInfo.fraction = FavoriteFraction.class;
// 分类
BottomBarInfo<Integer> categoryInfo = new BottomBarInfo<>(category,
ResourceTable.Media_category_normal,
ResourceTable.Media_category_selected,
defaultColor, tintColor);
categoryInfo.fraction = CategoryFraction.class;
// 发现
BottomBarInfo<Integer> findInfo = new BottomBarInfo<>(find,
ResourceTable.Media_recommend_normal,
ResourceTable.Media_recommend_selected,
defaultColor, tintColor);
findInfo.fraction = FindFraction.class;
// 我的
BottomBarInfo<Integer> profileInfo = new BottomBarInfo<>(profile,
ResourceTable.Media_profile_normal,
ResourceTable.Media_profile_selected,
defaultColor, tintColor);
profileInfo.fraction = ProfileFraction.class;
// 将每个条目的数据放入到集合
bottomInfoList.add(homeInfo);
bottomInfoList.add(favoriteInfo);
bottomInfoList.add(categoryInfo);
bottomInfoList.add(findInfo);
bottomInfoList.add(profileInfo);
// 设置底部导航栏的透明度
tabBottomLayout.setBarBottomAlpha(0.85f);
// 初始化所有的条目
tabBottomLayout.initInfo(bottomInfoList);
initFractionBarComponent();
tabBottomLayout.addBarSelectedChangeListener((index, prevInfo, nextInfo) ->
// 显示fraction
mFractionBarComponent.setCurrentItem(index));
// 设置默认选中的条目,该方法一定要在最后调用
tabBottomLayout.defaultSelected(homeInfo);
}
private void initFractionBarComponent() {
FractionManager fractionManage = mAbilitySliceProvider.getFractionManager();
BottomBarComponentProvider provider = new BottomBarComponentProvider(bottomInfoList, fractionManage);
mFractionBarComponent = (FractionBarComponent) mAbilitySliceProvider.findComponentById(ResourceTable.Id_fraction_bar_component);
mFractionBarComponent.setProvider(provider);
}
最后附上源码
欢迎阅读我的其它文章
鸿蒙系统—实现通用的下拉刷新组件