HarmonyOS实战: 城市选择功能的快速实现

本文涉及的产品
Elasticsearch Serverless检索通用型,资源抵扣包 100CU*H
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
简介: 本文详细介绍了在开发城市选择功能时,如何处理城市列表中的多音字、按字母顺序排列城市以及将首字母相同的城市分组的技术实现。首先,通过使用pinyin4js库处理多音字,确保每个城市名称的首字母正确。接着,利用Intl.Collator对城市数据进行字母排序。最后,通过遍历和条件判断,将首字母相同的城市分组,并使用ListItemGroup和sticky功能在UI中展示分组结果。文章强调了分组处理的复杂性,并鼓励读者动手实践以加深理解。

前言

最近在日常开发过程中,需要实现城市选择功能,同时支持模糊搜索。看似简单的功能动手实现起来却有很多难点。本篇文章详细记录开发过程中遇到的问题和对应的解决方法,希望能够帮助你,建议点赞收藏!

实现效果

需求分析

  • 处理城市列表中的多音字。
  • 城市列表要按照字母表的顺序排列
  • 将首字母相同的城市分组。

技术实现

  1. 在日常开发中,城市数据一般由接口获取或从本地 json 文件读取,毕竟城市数量和城市编码是固定不变的。不管是哪种方式获取城市数据,都无法保证数据的顺序符合需求,在处理数据顺序之前,首先要处理数据中的多音字,对常见多音字手动添加拼音字母,其余城市直接获取首字母,这里需要借助一个三方库pinyin4js 获取汉字的第一个拼音字母。
data?.forEach((city) => {
            if (city.cityName?.includes("长沙")) {
              city.letter = "CHANGSHASHI"
            } else if (city.cityName?.startsWith("重庆")) {
              city.letter = "CHONGQING"
            } else if (city.cityName?.startsWith("厦门")) {
              city.letter = "XIAMENSHI"
            } else {
              city.letter = pinyin4js.convertToPinyinString(city.cityName, '', pinyin4js.FIRST_LETTER).toUpperCase()
            }
          })
  1. 得到城市的字母后,这时就需要对城市数据按字母排序进行处理,借助系统通过collator 类的 compare 方法,对数据的字母进行排序。
let collator = new intl.Collator();
        data.sort((firstCity: HotCityBean, secondCity: HotCityBean) => {
          return collator.compare(firstCity.letter, secondCity.letter)
        })
  1. 得到排序后的数据,需要对数据进行分组,将首字母相同的城市放在同一个数组里,这一步有点复杂,需要慢慢看。
let target = data[0].letter?.charAt(0) ?? ""
        let cityType = new HotCityTypeBean()
        cityType.name = target;
        data.forEach((value, number) => {
          if (value.letter?.charAt(0) != target) {
            this.cityList.push(cityType)
            target = value.letter?.charAt(0) ?? ""
            cityType = new HotCityTypeBean()
            cityType.name = target
            cityType.city.push(value)
          } else {
            cityType.city.push(value)
          }
      
          .......
        })

首先得到第一条城市的首字母 A 作为目标项,然后使用 forEach 遍历数据,如果遍历的对象的首字母和目标项 A 不相等,则先认为首字母 A 的城市遍历结束,直接将相同字母 A 的数据放入集合,否则将相同字母 A 的数据放在一起(cityType.city.push(value))。

  1. 遍历到最后一条数据时,需要对最后一条数据进行处理,结束后将最后一个字母相同的数据存入城市集合。
if (number == data.length - 1) {
            if (!cityType.city.includes(value)) {
              cityType.city.push(value)
            }
            this.cityList.push(cityType)
          }
  1. 经过以上对数据的处理,终于得到了完整的城市数据,接下来就是直接展示列表即可。
List({ space: 14, initialIndex: 0, scroller: this.scroller }) {
          ForEach(this.cityList, (bean: HotCityTypeBean, index: number) => {
            if (index == 0) {
              ListItem() {
                Text() {
                  Span("当前城市: ")
                    .fontSize($r("app.float.sp_t5"))
                    .fontColor($r("app.color.color_S5"))
                  Span(this.cityName)
                    .fontSize($r("app.float.sp_t5"))
                    .fontColor($r("app.color.color_S7"))
                }
              }.margin({ top: $r("app.float.vp_10") })
            }
            ListItemGroup({ header: this.headView(bean.name) }) {
              ForEach(bean.city, (item: HotCityBean, childIndex: number) => {
                ListItem() {
                  Column() {
                    Text(`${item.cityName}`)
                      .height(44)
                      .fontSize($r('app.float.sp_t4'))
                      .width(FULL_WIDTH)
                      .onClick(() => {
                       
                      })
                    if (childIndex == bean.city.length - 1) {
                      Divider()
                        .color($r('app.color.color_S3'))
                        .height(0.5)
                        .vertical(false)
                    }
                  }.alignItems(HorizontalAlign.Start)
                }
              }, (item: HotCityBean, childIndex: number) => `${childIndex}${new Date()}`)
            }
          }, (bean: HotCityTypeBean, index: number) => `${index}${new Date()}`)
        } .sticky(StickyStyle.Header)
  1. 使用ListItemGroup 用来显示每组城市的首字母,sticky(StickyStyle.Header) 则是开启粘性标题,也就是滑动列表时,每组城市的首字母固定显示在上方。

总结

本文详细讲述了对城市数据的处理,包括对音字,首字母排序以及按首字母对数据进行分组处理,特别是分组处理这块的代码比较复杂,需要亲自动手尝试才能更好的理解,学会的小伙伴赶紧动手试试吧!如果您有更好的处理方式,欢迎评论区留言!

目录
相关文章
|
12天前
|
定位技术 UED
70. [HarmonyOS NEXT 实战案例九] 旅游景点网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的旅游景点网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的旅游景点应用。
28 1
|
12天前
|
容器
69.[HarmonyOS NEXT 实战案例九] 旅游景点网格布局(上)
本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现旅游景点网格布局。通过网格布局,我们可以以美观、规整的方式展示各种旅游景点信息,为用户提供良好的浏览体验。
27 1
|
12天前
|
UED
68.[HarmonyOS NEXT 实战案例八] 电影票务网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的电影票务网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的电影票务应用。
32 1
|
12天前
|
开发者 容器
67.[HarmonyOS NEXT 实战案例八] 电影票务网格布局(上)
在移动应用开发中,电影票务应用是一个常见的场景,用户可以通过应用查看正在热映的电影信息,并进行选座购票等操作。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现电影票务应用中的电影列表网格布局,帮助开发者掌握网格布局的基本用法和实现技巧。
26 1
|
12天前
|
UED
66.[HarmonyOS NEXT 实战案例七] 健身课程网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的健身课程网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的健身课程应用。
22 1
|
12天前
|
设计模式 UED
65. [HarmonyOS NEXT 实战案例七] 健身课程网格布局(上)
本教程将介绍如何使用HarmonyOS NEXT的GridRow和GridCol组件实现健身课程的网格布局展示。健身课程网格布局是一种常见的UI设计模式,适用于展示各种健身课程信息,包括课程名称、教练信息、课程时长、难度级别等。通过网格布局,用户可以快速浏览多个课程,并根据自己的需求选择合适的课程。
26 1
|
12天前
|
设计模式 容器
61.[HarmonyOS NEXT 实战案例五] 社交应用照片墙网格布局(上)
社交应用中的照片墙是一种常见的UI设计模式,它以网格形式展示用户的照片集合,让用户可以浏览、分享和互动。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现一个美观、灵活的社交应用照片墙网格布局。 在本教程中,我们将学习如何设计照片墙的数据结构、如何使用GridRow和GridCol组件创建网格布局、如何实现照片卡片,以及如何处理不同尺寸的照片。通过本教程,你将掌握使用GridRow和GridCol组件实现复杂网格布局的技巧。
23 1
|
12天前
64.[HarmonyOS NEXT 实战案例六] 餐饮菜单网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的餐饮菜单网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的餐饮菜单应用。
19 0
|
12天前
|
存储
63.[HarmonyOS NEXT 实战案例六] 餐饮菜单网格布局(上)
在移动应用开发中,餐饮类应用的菜单展示是一个常见的需求。一个设计良好的菜单布局不仅能够清晰地展示菜品信息,还能提升用户的点餐体验。本教程将详细讲解如何使用HarmonyOS NEXT的GridRow和GridCol组件实现一个美观实用的餐饮菜单网格布局。
26 0
|
12天前
|
UED
62. [HarmonyOS NEXT 实战案例五] 社交应用照片墙网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的社交应用照片墙网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的社交应用照片墙。
21 0