鸿蒙应用开发实战【21】— 筛选弹出面板三维筛选实现 鸿蒙应用开发实战【21】— 筛选弹出面板三维筛选实现前言欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net号码助手首页有一个「全部/已选N ⌄」筛选按钮点击后弹出一个气泡面板展示分类、卡号、状态三维筛选条件。用户可以在每个维度中选择一个值三个条件之间是 AND 关系共同决定列表的展示内容。本篇涵盖Flex FlexWrap 自动换行实现 chip 布局、筛选按钮状态联动已选条件计数、筛选面板 Builder 完整实现、三维数据过滤逻辑AND 条件组合、筛选重置 clear、与 bindPopup 集成。图1筛选弹出面板 Popup 结构 FlexWrap 换行原理 三维 AND 过滤逻辑一、筛选面板整体设计1.1 三维筛选简介维度数据来源选项示例状态变量分类CATEGORIES 常量数组全部/社交/购物/金融/工具filterCatIdx: number卡号数据库 CardDao.listAll()全部/主卡/副卡/工作卡filterCardIdx: number状态STATUS_FILTERS 常量数组全部/使用中/待换绑/待注销/已停用filterStatIdx: number三个维度的索引值0均代表「全部」非0代表选择了具体条件。1.2 筛选按钮// 首页筛选触发按钮Row({space:3}){Text(this.activeFilterCount()0?已选${this.activeFilterCount()}:全部).fontSize(12).fontWeight(AppFonts.WEIGHT_SEMIBOLD).fontColor(this.activeFilterCount()0?#3E68E0:AppColors.TEXT_2)Text(⌄).fontSize(10).fontColor(this.activeFilterCount()0?#3E68E0:AppColors.TEXT_3)}.padding({left:11,right:11,top:6,bottom:6}).backgroundColor(this.activeFilterCount()0?AppColors.PRIMARY_BG:AppColors.CARD_B).border({width:1,color:this.activeFilterCount()0?#4D4F7CFF:AppColors.LINE,radius:14}).bindPopup($$this.showFilter,{builder:()this.FilterPopoverBuilder(),placement:Placement.Bottom,popupColor:#FFFFFF,onStateChange:(e){if(!e.isVisible){this.showFilterfalse}}}).onClick((){this.showFilter!this.showFilter})按钮的样式会根据是否有活跃筛选条件而变化——有选中项时显示蓝色高亮边框和「已选 N」计数。二、筛选面板 Builder 实现2.1 面板整体结构BuilderprivateFilterPopoverBuilder(){Column(){// 分类维度this.FilterSection(分类,CATEGORIES,this.filterCatIdx,(idx:number){this.filterCatIdxidx})// 卡号维度this.FilterSection(卡号,this.getCardLabels(),this.filterCardIdx,(idx:number){this.filterCardIdxidx})// 状态维度this.FilterSection(状态,STATUS_FILTERS,this.filterStatIdx,(idx:number){this.filterStatIdxidx})// 底部重置按钮Button(重置).onClick(()this.resetFilters())}.width(220).padding(14)}2.2 筛选维度子组件BuilderprivateFilterSection(title:string,items:string[],selectedIdx:number,onSelect:(idx:number)void){Column(){Text(title).fontSize(11).fontColor(AppColors.TEXT_3).fontWeight(AppFonts.WEIGHT_SEMIBOLD).alignSelf(ItemAlign.Start).margin({bottom:8})// Flex FlexWrap 实现 chip 自动换行Flex({wrap:FlexWrap.Wrap}){ForEach(items,(item:string,idx:number){Text(item).fontSize(12).fontWeight(AppFonts.WEIGHT_MEDIUM).fontColor(selectedIdxidx?#FFFFFF:AppColors.TEXT_2).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(selectedIdxidx?AppColors.PRIMARY:AppColors.CARD_B).border({width:1,color:selectedIdxidx?#00000000:AppColors.LINE,radius:14}).margin({right:6,bottom:6}).onClick(()onSelect(idx))},(item:string)item)}}.margin({bottom:14}).alignItems(HorizontalAlign.Start)}2.3 Chip 选中态每个 chip 是一个Text组件通过selectedIdx idx来判断是否选中状态backgroundColorfontColorborder选中AppColors.PRIMARY#4F7CFF#FFFFFF透明未选中AppColors.CARD_B#FFFFFFAppColors.TEXT_2AppColors.LINE三、Flex FlexWrap 自动换行3.1 FlexWrap 的必要性筛选选项数量不固定如果使用Row容器当选项超出一行时会被裁剪。使用Flex({ wrap: FlexWrap.Wrap })可以实现自动换行。// ❌ Row单行不换行超出裁剪Row({space:6}){Text(全部)Text(社交)Text(购物)Text(金融)Text(工具)// 如果宽度不够这个会被裁剪}// ✅ Flex FlexWrap.Wrap多行自动换行Flex({wrap:FlexWrap.Wrap}){Text(全部).margin({right:6,bottom:6})Text(社交).margin({right:6,bottom:6})Text(购物).margin({right:6,bottom:6})Text(金融).margin({right:6,bottom:6})Text(工具).margin({right:6,bottom:6})// 自动换到下一行}3.2 spacing 的关键参数Flex({wrap:FlexWrap.Wrap}){// 每个 chip 通过 margin 控制间距Text(chip).margin({right:6,bottom:6})// right: 水平方向 chip 之间的间距// bottom: 垂直方向行与行之间的间距}3.3 Flex 与 Row 的对比对比项RowFlex FlexWrap.Wrap布局方向水平单行水平多行自动换行超出处理裁剪/溢出自动折行适用场景固定数量的按钮组数量不固定的标签列表号码助手使用底部操作按钮筛选面板 chip 列表 ✅四、筛选状态管理4.1 活跃条件计数/** * 统计当前激活的筛选条件数 * 每个维度非 0 代表有选中条件 */privateactiveFilterCount():number{letn0if(this.filterCatIdx!0)n// 分类有选中if(this.filterCardIdx!0)n// 卡号有选中if(this.filterStatIdx!0)n// 状态有选中returnn}4.2 筛选重置privateresetFilters():void{this.filterCatIdx0this.filterCardIdx0this.filterStatIdx0this.showFilterfalse// 重置后关闭面板}4.3 三维过滤逻辑/** * AND 条件组合过滤 * 每个维度 idx0 表示「全部」不参与过滤 */privategetFilteredRows():AppRow[]{returnthis.rows.filter((r:AppRow){constcatOkthis.filterCatIdx0||r.binding.categoryCATEGORIES[this.filterCatIdx]constcardOkthis.filterCardIdx0||r.cardLabelthis.getCardLabels()[this.filterCardIdx]conststatOkthis.filterStatIdx0||r.binding.statusSTATUS_FILTERS[this.filterStatIdx]returncatOkcardOkstatOk// 三个条件同时满足})}过滤逻辑图解维度idx0idx≠0分类不过滤全部匹配 CATEGORIES[idx]卡号不过滤全部匹配 cards[idx-1].label状态不过滤全部匹配 STATUS_FILTERS[idx]三个条件的 AND 关系简化为任何一个维度是非 0 时才参与过滤否则跳过。五、本篇小结知识点核心要点FlexWrap.Wrapchip 标签自动换行搭配 margin right/bottom 控制间距Chip 选中态选中 蓝色填充未选中 白色描边activeFilterCount统计已选条件数驱动按钮样式变化三维 AND 过滤catIdx/cardIdx/statIdx 三个维度独立过滤resetFilters全部重置为 0 并关闭面板参考资料鸿蒙应用开发实战【17】— bindPopup 气泡弹出与筛选面板鸿蒙应用开发实战【05】— 首页开发与状态管理Flex 容器 APIFlexWrap 枚举Builder 装饰器bindPopup API如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netFlex 容器文档https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-flexFlexWrap 换行说明https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-appendix-enums