先看效果
弹窗利用了半模态弹窗,绑定到了button上面,选择器使用了官方的TextPicker,
具体实现看下面代码,关键部分加了注释,
需要注意的点就是数据源,省市区传入TextPicker的格式要正确
代码仓库链接
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';
import { CommonConstants } from '../common/CommonConstants';
/**
* 三级联动地址选择器
*/
@Component
export struct AddressSelectView {
// 平板或折叠屏展开态在中间显示
@State isCenter: boolean = true;
// 是否显示半屏模态页面
@State isPresent: boolean = false;
// 半模态高度
@State sheetHeight: number = 300;
// 是否显示控制条
@State showDragBar: boolean = true;
// 省市区数据下标
addressSelectIndex: number | number [] = [0, 0, 0];
//选中的省市区名字
addressSelectText: Array<string> = []
// 省市区数据存放文件地址
fileName: string = 'regionsdata.json';
// 存放省市区数据
cascade: Array<TextCascadePickerRangeContent> = [];
@State selectText: string = ''
aboutToAppear(): void {
this.loadRegion();
}
build() {
Column({ space: 10 }) {
Text(this.selectText).margin(10).padding(10)
Button('选择地址').bindSheet($$this.isPresent, this.halfModalAddressSelectView(), {
// TextInput绑定半模态转场
height: this.sheetHeight, // 半模态高度
dragBar: this.showDragBar, // 是否显示控制条
// 平板或折叠屏展开态在中间显示
// preferType: this.isCenter ? SheetType.CENTER : SheetType.POPUP,
backgroundColor: $r('app.color.editaddress_btn_bgc'),
showClose: false, // 是否显示关闭图标
shouldDismiss: ((sheetDismiss: SheetDismiss) => { // 半模态页面交互式关闭回调函数
sheetDismiss.dismiss();
})
})
.onBlur(() => {
if (!this.isPresent) { // 当省市区输入框失焦且半模态关闭,将点击状态置为false
}
})
.onClick(() => {
this.isPresent = true;
})
}
}
@Builder
halfModalAddressSelectView() { // 半模态窗口页面
Column() {
Row() {
Text('取消')
.titleBtnStyle()
.onClick(() => {
this.isPresent = !this.isPresent;
})
Text('地区选择')
.fontColor(Color.Black)
.fontSize(CommonConstants.HALF_FONTSIZE_TITLE)
Text('确认')
.titleBtnStyle()
.onClick(() => {
this.isPresent = !this.isPresent; // 关闭半模态
// this.getSelectedPlace();
this.getSelectedCityName();
})
}
.padding({
left: 50,
right: 50,
top: 15,
bottom: 15
})
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.SpaceBetween)
.backgroundColor($r('app.color.editaddress_bind_sheet_title_bgc'))
.width(CommonConstants.FULL_PERCENT)
TextPicker({
range: this.cascade,//省市区数据
selected: this.addressSelectIndex//默认选中的index
})
.onChange((value: string | string[], index: number | number[]) => {
//返回选择项下标数组
if (index instanceof Array) {
this.addressSelectIndex = index;
}
//返回选择项文本数组
if (value instanceof Array) {
this.addressSelectText = value
}
})// 设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。
.textStyle({
color: $r('app.color.editaddress_textStyle_font_color'),
font: {
size: 16,
weight: FontWeight.Regular
}
})// 设置选中项的文本颜色、字号、字体粗细。
.selectedTextStyle({
color: $r('app.color.editaddress_selectedTextStyle_font_color'),
font: {
size: $r('app.string.editaddress_selectedTextStyle_font_size'),
weight: FontWeight.Medium
}
})
.padding({ top: CommonConstants.PADDING })
}
}
/**
* 从文件中读取省市区json数据
*/
async loadRegion(): Promise<void> {
try {
// 通过getRawFileContent()获取resources/rawfile目录下对应的文件内容,得到一个字节数组
getContext(this).resourceManager.getRawFileContent(this.fileName, (_: BusinessError, value: Uint8Array) => {
let rawFile = value;
let textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true });
let retStr =
textDecoder.decodeToString(rawFile, { stream: false }); // 再用@ohos.util (util工具函数)的TextDecoder给它解析出来
this.cascade = JSON.parse(retStr);
})
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
console.error(`callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
}
}
/**
* 从TextPicker返回选中的数据中逐级查找省、市、区的名称,并将其组合成一个完整的地址字符串。
*/
getSelectedPlace() {
if (this.addressSelectIndex instanceof Array) {
let province = this.cascade[this.addressSelectIndex[0]]; // 获取省信息
let areaName = ""; // 存储最终构建的省市区名称
if (province) {
areaName += this.cascade[this.addressSelectIndex[0]].text; // 省的名称添加到容器里
if (province.children) { // 检查是否有市的信息
let city = province.children[this.addressSelectIndex[1]]; // 市的名称添加到容器里
if (city) {
areaName += city.text;
if (city.children) { // 检查是否有区的信息
areaName += city.children[this.addressSelectIndex[2]].text; // 区的名称添加到容器里
}
}
}
}
this.selectText = areaName; // 将取出的省市区拼接的字符串回填给TextInput
return;
}
}
/**
* 遍历返回数据,组合成地址
*/
getSelectedCityName() {
let nameTemp = ''
this.addressSelectText.forEach(element => {
nameTemp += element
});
this.selectText = nameTemp
}
}
@Extend(Text)
function titleBtnStyle() {
.fontColor($r('app.color.editaddress_font_color'))
.fontSize(CommonConstants.HALF_FONTSIZE)
.fontWeight(CommonConstants.HALF_FONT_WEIGHT)
}
参考:
编辑收货地址案例
TextPicker