HarmonyOS应用开发:自定义地址选择组件

前言

本示例介绍如何使用bindSheet,changeIndex,onAreaChange实现带切换动效的自定义地址选择组件。

效果图预览

使用说明

  1. 进入页面,点击场景一中"所在地区"一栏,可拉起省市区的地址选择弹窗。选择完区后,弹窗自动关闭,"所在地区"一栏显示当前选择的省市区名。

  2. 进入页面,点击场景二中的'获取地址信息'按钮,可以查看省市区名和相应的id。点击"所在地区"一栏,在拉起的地址选择弹窗里选择另一个省市区后,再次点击'获取地址信息'按钮,会显示最新选择的省市区的信息。

实现思路

  1. 使用getRawFileContentSync从rawfile目录下读取省市区json文件数据,使用util.TextDecoder进行解码。

    getAddressData(): Array { // 从rawfile本地json文件中获取数据 const value = getContext().resourceManager.getRawFileContentSync(this.jsonFileDir); // 解码为utf-8格式 const textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true }); const textDecoderResult = textDecoder.decodeToString(new Uint8Array(value.buffer)); const jsonObj: JsonObjType = JSON.parse(textDecoderResult) as JsonObjType; const modelBuckets: Array = \[\]; // 映射json数据为model对象 const modelObj = jsonObj.addressList; for (let i = 0; i < modelObj.length; i++) { const contactTemp = new Province(modelObji.code, modelObji.name, modelObji.children); // 从json中读取每个省数据写入modelBuckets modelBuckets.push(contactTemp); } return modelBuckets; }

  2. 使用bindSheet绑定地址选择半模态弹窗页面。

    Row() { // ... } .width( r ( ′ a p p . s t r i n g . c u s t o m a d d r e s s p i c k e r f u l l s i z e ′ ) ) . h e i g h t ( r('app.string.custom_address_picker_full_size')) .height( r(′app.string.customaddresspickerfullsize′)).height(r('app.float.custom_address_picker_size_forty_eight')) .onClick(() => { // 显示地址选择半模态弹窗页面 this.isShow = true; this.currentIndex = AddressType.Province; }) .bindSheet($$this.isShow, this.addressSelectPage(), { height: $r('app.string.custom_address_picker_percent_seventy'), // 半模态弹窗高度 showClose: false, // 设置不显示自带的关闭图标 dragBar: false, onDisappear: () => { // 退出地址选择半模态弹窗页面时,重置相关参数 this.animationDuration = 0; // 如果当前省市区没选全,则清空当前选择的地址信息 if (this.currentSelectInfo.region === '') { this.currentSelectInfo.provinceId = ''; this.currentSelectInfo.cityId = ''; this.currentSelectInfo.regionId = ''; this.currentSelectInfo.province = ''; this.currentSelectInfo.city = ''; this.currentSelectInfo.region = ''; this.cityList = \[\]; this.regionList = \[\]; } } })

  3. 使用changeIndex控制省市区列表TabContent切换。使用组件区域变化回调onAreaChange获取选择的省市区Text组件宽度,存入textInfos数组,用于后续计算选择省市区名后下方下滑线动画水平偏移量leftMargin。

    Text(${params.name === '' ? '请选择' : params.name} ) .height( r ( ′ a p p . s t r i n g . c u s t o m a d d r e s s p i c k e r f u l l s i z e ′ ) ) . f o n t S i z e ( r('app.string.custom_address_picker_full_size')) .fontSize( r(′app.string.customaddresspickerfullsize′)).fontSize(r('app.float.custom_address_picker_size_sixteen')) .fontWeight(this.currentIndex === params.index ? Constants.FONT_WEIGHT_FIVE_HUNDRED : Constants.FONT_WEIGHT_FOUR_HUNDRED) .fontColor(this.currentIndex === params.index ? r ( ′ a p p . c o l o r . c u s t o m a d d r e s s p i c k e r f o n t c o l o r b l a c k ′ ) : r('app.color.custom_address_picker_font_color_black') : r(′app.color.customaddresspickerfontcolorblack′):r('app.color.custom_address_picker_font_color_gray')) .constraintSize({ maxWidth: 'calc(33%)' }) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(Constants.SIZE_ONE) .onClick(() => { // 使用changeIndex控制省市区列表TabContent切换 this.controller.changeIndex(params.index); }) .id(params.index.toString()) .onAreaChange((oldValue: Area, newValue: Area) => { // 使用组件区域变化回调onAreaChange获取选择的省市区Text组件宽度,存入textInfos数组,用于后续计算选择省市区名后下方下滑线动画水平偏移量leftMargin // 组件区域变化时获取当前Text的宽度newValue.width和x轴相对位置newValue.position.x this.textInfosparams.index = newValue.position.x as number, newValue.width as number; if (this.currentIndex === params.index && params.index === AddressType.Province) { // 计算选择的省市区名下方的下滑线偏移量 this.leftMargin = (this.textInfosthis.currentIndex1 - Constants.DIVIDER_WIDTH) / 2; } })

  4. 在选择完区名后,使用JSON.parse(JSON.stringify(xxx))深拷贝选择的省市区数据,用于后续操作中需要加载上一次选择的完整省市区数据。

    List() { ForEach(this.regionList, (item: CommonAddressList) => { ListItem() { this.areaNameItem(AddressType.Region, item) }.onClick(() => { // 记录选择的区信息 this.currentSelectInfo.regionId = item.code; this.currentSelectInfo.region = item.name; this.provinceCityRegion = this.currentSelectInfo.province + this.currentSelectInfo.city + this.currentSelectInfo.region; // 选择区后,退出地址选择半模态弹窗页面 this.isShow = false; // 将当前选中省市区信息保存到lastSelectInfo this.lastSelectInfo.provinceId = this.currentSelectInfo.provinceId; this.lastSelectInfo.province = this.currentSelectInfo.province; this.lastSelectInfo.cityId = this.currentSelectInfo.cityId; this.lastSelectInfo.city = this.currentSelectInfo.city; this.lastSelectInfo.regionId = this.currentSelectInfo.regionId; this.lastSelectInfo.region = this.currentSelectInfo.region; // TODO 知识点:在选择完区名后,使用JSON.parse(JSON.stringify(xxx))深拷贝选择的省市区数据,用于后续操作中需要加载上一次选择的完整省市区数据 // 深拷贝保存到相应的变量中 this.lastCityList = JSON.parse(JSON.stringify(this.cityList)); this.lastRegionList = JSON.parse(JSON.stringify(this.regionList)); this.address = JSON.parse(JSON.stringify(this.lastSelectInfo)); }) }, (item: CommonAddressList) => JSON.stringify(item)) }

总结

本示例中如果当前点击选择的省或者市与之前选择一样,则跳过省、市数据获取,直接调用changeIndex(AddressType.City)切换到下一级地区列表,减少冗余查询以提升性能。

如果您想系统深入地学习 HarmonyOS 开发或想考取HarmonyOS认证证书,欢迎加入华为开发者学堂:

请点击→: HarmonyOS官方认证培训

相关推荐
硬核子牙7 分钟前
你管这破玩意叫ChatGPT?
人工智能·chatgpt·程序员
风华圆舞10 分钟前
鸿蒙 + Flutter 下 AI 页面的状态协同设计
人工智能·flutter·harmonyos
互联网散修20 分钟前
鸿蒙实战:仿小红书“我”的页面——从分层架构到沉浸式交互
交互·harmonyos
TinssonTai20 分钟前
这个 VS Code 插件让我的 AI Coding 又快又稳 - 旧瓶装新酒
前端·人工智能·程序员
林九生22 分钟前
【实用技巧】MySQL 绿色版一键路径更新脚本详解 —— update_path.bat 深度解析
android·数据库·mysql
故渊at2 小时前
第十三板块:Android 综合架构与未来演进 | 第三十一篇:Android 架构演进与 Fuchsia OS 的挑战
android·架构·宏内核·微内核·fuchsia·ipc 性能博弈
aqi002 小时前
一文速览 HarmonyOS 6.1.1 推出的十个新特性
android·华为·harmonyos·鸿蒙·harmony
木咺吟2 小时前
鸿蒙原生应用实战(三):游戏详情页与交互功能 — 400行ArkTS深度实践
harmonyos
matrixmind12 小时前
aiomysql:异步场景下的 MySQL 驱动
android·数据库·mysql·其他
随遇丿而安2 小时前
第8周:弹窗 / 提示组件全功能与弹窗优化
android