#夏日挑战赛# HarmonyOS应用开发-实现底部导航栏功能 原创 精华
OS中的塔秋莎
发布于 2022-7-26 20:38
浏览
4收藏
[本文正在参加星光计划3.0–夏日挑战赛] https://ost.51cto.com/posts/13641
前言
HarmonyOS应用开发最常见的一种功能就是底部导航栏,今天就带着大家一起来感受不一样的底部导航栏的实现-自定义Component的方式。
自定义View
创建布局
首先创建一个item_route.xml的布局,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_content"
ohos:alignment="center"
ohos:orientation="vertical">
<Image
ohos:id="$+id:img"
ohos:height="25vp"
ohos:width="25vp"
ohos:bottom_margin="1vp"
ohos:scale_mode="inside"/>
<Text
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="match_content"
ohos:text_color="$color:hintColor"
ohos:text_size="10vp"/>
</DirectionalLayout>
创建自定义Component的类RouteView.java
public class RouteView extends DirectionalLayout {
private static final int ITEM_LAYOUT = ResourceTable.Layout_item_route;
private List<Data> data;
private Callback callback;
public RouteView(Context context) {
this(context, null);
}
public RouteView(Context context, AttrSet attrSet) {
this(context, attrSet, null);
}
public RouteView(Context context, AttrSet attrSet, String styleName) {
super(context, attrSet, styleName);
init();
}
private void init() {
setOrientation(HORIZONTAL); //设置水平方向
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public void setData(DataBuilder builder) {
setData(builder, 0);
}
public void setData(DataBuilder builder, int p) {
data = builder.build();
createItems();
select(p);
}
public void select(int p) {
for (int i = 0; i < data.size(); i++) {
data.get(i).selected = i == p;
refreshItemData(i);
}
}
private void createItems() {
data.forEach(d -> addComponent(createItem(),
new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT, HORIZONTAL, 1)));
}
private Component createItem() {
Component component = LayoutScatter.getInstance(getContext())
.parse(ITEM_LAYOUT, null, false);
ViewHolder holder = new ViewHolder();
holder.img = (Image) component.findComponentById(ResourceTable.Id_img);
holder.text = (Text) component.findComponentById(ResourceTable.Id_text);
component.setTag(holder);
component.setClickedListener(v -> {
int p = getChildIndex(v);
if (p < 0) return;
select(p);
if (callback != null) callback.onItemClicked(p);
});
return component;
}
private void refreshItemData(int p) {
Component component = getComponentAt(p);
Object tag = component.getTag();
if (!(tag instanceof ViewHolder)) return;
ViewHolder holder = (ViewHolder) tag;
holder.text.setText(data.get(p).text);
holder.img.setPixelMap(data.get(p).getImageRes());
holder.text.setTextColor(ResUtil.getColorObj(getContext(), data.get(p).getColorRes()));
}
public interface Callback {
void onItemClicked(int p);
}
static class ViewHolder {
Text text;
Image img;
}
static class Data {
String text;
int imageRes, selectedImageRes;
int colorRes, selectedColorRes;
boolean selected;
public Data(String text, int imageRes, int selectedImageRes, int colorRes, int selectedColorRes) {
this.text = text;
this.imageRes = imageRes;
this.selectedImageRes = selectedImageRes;
this.colorRes = colorRes;
this.selectedColorRes = selectedColorRes;
}
public int getImageRes() {
return selected ? selectedImageRes : imageRes;
}
public int getColorRes() {
return selected ? selectedColorRes : colorRes;
}
}
public static class DataBuilder {
private final List<Data> data = new ArrayList<>();
public DataBuilder add(String text, int imageRes, int selectedImageRes, int colorRes, int selectedColorRes) {
data.add(new Data(text, imageRes, selectedImageRes, colorRes, selectedColorRes));
return this;
}
public List<Data> build() {
return data;
}
}
}
- 在项目的build.gradle中添加依赖,如下:
api 'com.gitee.chinasoft_ohos:ohos-extension:1.0.0'
- 这里我们定义了一个接口Callback,用于点击选项卡的回调:代码如下:
public interface Callback { void onItemClicked(int p); }
- 定义了一个集合List<Data> 用于存放item资源,Data数据结构如下:
static class Data {
String text;
int imageRes, selectedImageRes;
int colorRes, selectedColorRes;
boolean selected;
/*
* text:显示文本
* imageRes:未选中的图片资源文件
* selectedImageRes:选中的资源文件
* colorRes: 未选中的文本颜色
* selectedColorRes: 选中时文本的颜色
* */
public Data(String text, int imageRes, int selectedImageRes, int colorRes, int selectedColorRes) {
this.text = text;
this.imageRes = imageRes;
this.selectedImageRes = selectedImageRes;
this.colorRes = colorRes;
this.selectedColorRes = selectedColorRes;
}
//获取图片资源
public int getImageRes() {
return selected ? selectedImageRes : imageRes;
}
//获取文本颜色
public int getColorRes() {
return selected ? selectedColorRes : colorRes;
}
}
- 另外,我们通过builder建造者模式,可以动态的添加和删除item,代码如下:
public static class DataBuilder { private final List<Data> data = new ArrayList<>(); public DataBuilder add(String text, int imageRes, int selectedImageRes, int colorRes, int selectedColorRes) { data.add(new Data(text, imageRes, selectedImageRes, colorRes, selectedColorRes)); return this; } public List<Data> build() { return data; } }
应用开发整体框架
1、首先在MainAbility类中继承FractionAbility.
public class MainAbility extends FractionAbility{
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
}
}
2、创建两个Fraction的布局文件fr_home.xml、fr_me.xml。
fr_home.xml:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:background_element="$color:bgColor"
ohos:alignment="center"
ohos:orientation="vertical">
<Text
ohos:height="match_content"
ohos:width="match_content"
ohos:text="首页页面"/>
</DirectionalLayout>
fr_me.xml:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:background_element="$color:bgColor"
ohos:alignment="center"
ohos:orientation="vertical">
<Text
ohos:height="match_content"
ohos:width="match_content"
ohos:text="我的页面"/>
</DirectionalLayout>
3、创建HomeFraction、MeFraction类:
HomeFraction:
public class HomeFraction extends Fraction {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
}
@Override
protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
return scatter.parse(ResourceTable.Layout_fr_home, null, false);
}
}
MeFraction:
public class MeFraction extends Fraction {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
}
@Override
protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
return scatter.parse(ResourceTable.Layout_fr_me, null, false);
}
}
4、在MainAbilitySlice类中初始化Fraction,实现RouteView.Callback回调。
private void initFraction() {
fractions = new ArrayList<>();
homeFraction = new HomeFraction(this);
fractions.add(homeFraction);
fractions.add(new MeFraction(this));
showFraction(0);
}
private void initView() {
routeView = (RouteView) findComponentById(ResourceTable.Id_route);
routeView.setCallback(this);
RouteView.DataBuilder builder = new RouteView.DataBuilder()
.add("首页", ResourceTable.Media_home, ResourceTable.Media_home_s ,
ResourceTable.Color_hintColor, ResourceTable.Color_tabTextColor)
.add("我的", ResourceTable.Media_me, ResourceTable.Media_me_s,
ResourceTable.Color_hintColor, ResourceTable.Color_tabTextColor);
routeView.setData(builder);
}
......
private void showFraction(int p) {
scheduler = ((FractionAbility) getAbility()).getFractionManager().startFractionScheduler();
for (int i = 0; i < fractions.size(); i++) {
Fraction f = fractions.get(i);
if (i == p) scheduler.replace(ResourceTable.Id_container, f);
else scheduler.remove(f);
}
scheduler.submit();
}
......
@Override
public void onItemClicked(int p) {
showFraction(p);
}
效果图如下所示:
总结
本篇的难点在于使用自定义Component的方式实现了底部Tab导航的功能,可以使代码方便复用。
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
HarmonyOS应用开发框架.rar 1.25M 120次下载
已于2022-7-27 09:19:40修改
赞
10
收藏 4
回复
相关推荐
如有任何错误或者不当的地方,欢迎指出,本人虚心接受并改正。
希望下次能把效果展示放上面一点
学习到了
好的,多谢提醒
一起学习
学到了 牛掰
学习了
共同学习,共同进步
共同学习,共同进步
共同进步