HarmonyOS鸿蒙NEXT中自定义组件下拉选择框
HarmonyOS鸿蒙NEXT中自定义组件下拉选择框
背景
在项目中遇到了一个下拉选择框组件的开发需求:
- 选择框的三角箭头需要在点击时跟随转动。
- 弹出的选择框需要基本满框弹出。
- 选择框显示选择的项的方式为后面加一个✔的符号或图片。
- 选择框选择不是第一个默认的时候,需要提供一个不同颜色的显示提醒用户。
- 选择框需要提供方法,实现选择第一列的数值的时候,可以格式化成其他的文字内容。
根据测试发现,系统自带的Select组件的自定义无法满足想要的效果,因此根据多次的测试后,选择使用Toggle+bindMenu的方式,实现对组件的最大自定义封装。并提供了Option设置类,代码复制后可以直接使用。
实现效果
代码文件
SelectDemo
调用使用页面文件
@Entry
@ComponentV2
export struct SelectDemo {
@Local Option: ToggleMenuOption = new ToggleMenuOption()
@Local DistanceOption: ToggleMenuOption = new ToggleMenuOption()
aboutToAppear(): void {
this.Option.Items = ["推荐排序", "距离最近", "评分最高"];
this.Option.SelectValue = "推荐排序";
this.Option.SelectedIndex = 0;
this.DistanceOption.Items = ["不限", "500 米", "1000 米", "3000 米", "5000 米", "10000 米"];
this.DistanceOption.SelectValue = "位置距离";
this.DistanceOption.SelectedIndex = 0;
this.DistanceOption.ToggleBackground = "#e6eaeb"
this.DistanceOption.SelectValueFormatAction = (value) => {
if (value == "不限") {
return "位置距离";
}
return value;
}
}
build() {
Column({ space: 20 }) {
ToggleMenu({ Option: this.Option })
ToggleMenu({ Option: this.DistanceOption })
}
.width("100%")
.height("100%")
}
}
ToggleMenuOption
自定义组件配置类,提供了是否显示菜单,选中字符、菜单索引等组件内容设置,大家可以根据自己的需求修改当前类的内容,可以添加和删减
@ObservedV2
export class ToggleMenuOption {
/**
* 是否展示菜单
*/
@Trace IsShowMenu: boolean = false
/**
* 菜单集合
*/
@Trace Items: string[] = []
/**
* 选中字符串
*/
@Trace SelectValue: string = ""
/**
* 菜单选择的索引
*/
@Trace SelectIndex: number = -1
/**
* 选择器默认背景颜色
*/
@Trace ToggleBackground: ResourceColor = "#f4f6f5"
/**
* 选择不是第一个选项时显示的背景颜色
*/
@Trace ToggleUnFirstBackground: ResourceColor = "#c2d3f4"
/**
* 选择按钮高度
*/
@Trace ToggleHeight: Length = 35
/**
* 选择按钮宽度
*/
@Trace ToggleWidth: Length = 120
/**
* 菜单选项高度
*/
@Trace MenuItemHeight: Length = 40
/**
* 菜单展示宽度
*/
@Trace MenuWidth: Length = "80%"
/**
* 菜单内缩值
*/
@Trace MenuPadding: Padding = {
top: 10,
bottom: 10,
right: 20,
left: 20
}
/**
* 选择内容需要对应格式化时
*/
@Trace SelectValueFormatAction?: (value: string) => string
/**
* 菜单点击切换方法
*/
@Trace SelectChangeEvent?: (oldValue: number, newValue: number) => void
}
ToggleMenu
封装组件
import { ToggleMenuOption } from "../Models/ToggleMenuOption";
@ComponentV2
export struct ToggleMenu {
@Param Option: ToggleMenuOption = new ToggleMenuOption()
aboutToAppear(): void {
}
build() {
Column() {
Toggle({ type: ToggleType.Button, isOn: $$this.Option.IsShowMenu }) {
Row() {
Text(this.Option.SelectValue)
.fontWeight(FontWeight.Bold)
Path()
.width(20)
.height(20)
.commands(`M${vp2px(4)} ${vp2px(7)} L${vp2px(10)} ${vp2px(15)} L${vp2px(16)} ${vp2px(7)} Z`)
.rotate(this.Option.IsShowMenu ? {
centerX: "50%",
centerY: "50%",
angle: 180
} : {
angle: 0
})
}
.justifyContent(FlexAlign.SpaceBetween)
.padding({ left: 15, right: 15 })
.height("100%")
.width("100%")
}
.backgroundColor(this.Option.SelectedIndex == 0 ? this.Option.ToggleBackground :
this.Option.ToggleUnFirstBackground)
.selectedColor(this.Option.SelectedIndex == 0 ? this.Option.ToggleBackground : this.Option.ToggleUnFirstBackground)
.width(this.Option.ToggleWidth)
.height(this.Option.ToggleHeight)
.bindMenu(this.Option.IsShowMenu, this.SortMenuBuilder(), {
placement: Placement.Bottom,
onDisappear: () => {
if (this.Option.IsShowMenu) {
this.Option.IsShowMenu = false;
}
}
})
}
.height(this.Option.ToggleHeight)
}
@Builder
SortMenuBuilder() {
Column() {
ForEach(this.Option.Items, (value: string, index: number) => {
Row() {
Text(value)
Image($r('app.media.YesIcon'))
.width(20)
.height(20)
.fillColor("#282828")
.visibility(this.Option.SelectedIndex == index ? Visibility.Visible : Visibility.None)
}
.borderColor("#f7f7f7")
.borderWidth({
bottom: index == this.Option.Items.length - 1 ? 0 : 1
})
.justifyContent(FlexAlign.SpaceBetween)
.alignItems(VerticalAlign.Center)
.height(this.Option.MenuItemHeight)
.width("100%")
.onClick(() => {
if (this.Option.SelectChangeEvent && this.Option.SelectedIndex != index) {
this.Option.SelectChangeEvent(this.Option.SelectedIndex, index);
}
if (this.Option.SelectValueFormatAction) {
this.Option.SelectValue = this.Option.SelectValueFormatAction(value);
} else {
this.Option.SelectValue = value;
}
this.Option.SelectedIndex = index;
this.Option.IsShowMenu = false;
})
})
}
.padding(this.Option.MenuPadding)
.width(this.Option.MenuWidth)
}
}
总结
上述文章是对下拉框选择组件的一种封装和实现的方式,其中也遇到了一些问题,比如说:
- 菜单组件的宽度设置成“100%”的时候,菜单会自动内缩一段距离,然后也没有办法进行调整,如果弹出菜单内容的宽度也设置成100%的话,会出现超出界面不显示的问题。(希望后面会解决这个问题)
希望这篇文章对大家可以有所帮助,或者有什么可以改进的地方,欢迎大家交流
更多关于HarmonyOS鸿蒙NEXT中自定义组件下拉选择框的实战教程也可以访问 https://www.itying.com/category-93-b0.html
1 回复
更多关于HarmonyOS鸿蒙NEXT中自定义组件下拉选择框的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙NEXT中,自定义下拉选择框可以通过Picker
组件实现。首先,在resources
目录下定义选择项,然后在布局文件中使用Picker
组件,并通过setValueChangedListener
监听选择变化。示例代码如下:
<Picker
ohos:id="$+id:picker"
ohos:width="match_parent"
ohos:height="wrap_content"
ohos:selected_text_size="30fp"
ohos:normal_text_size="20fp"/>
Picker picker = (Picker) findComponentById(ResourceTable.Id_picker);
picker.setDisplayedData(new String[]{"选项1", "选项2", "选项3"});
picker.setValueChangedListener((picker, oldVal, newVal) -> {
// 处理选择变化
});
通过这种方式,可以灵活定制下拉选择框的样式和功能。