鸿蒙自定义下拉选择组件开发指南

为什么要做这个
今天在开发鸿蒙应用时,我遇到了一个棘手的样式定制问题:官方提供的 Select 组件 虽然稳定性和易用性都很出色,但在实际开发中存在限制:

官方文档中部分样式属性需要在 API 20 及以上版本才能使用,而我的项目需要兼容更低版本,导致样式定制需求完全无法满足。

为解决这个问题,我翻遍了鸿蒙官方文档,却始终没找到适配低版本的解决方案;上网搜索时,相关内容要么是收费教程,要么是基于旧版 API 的过时文章。

最终,我决定自己 “手搓” 一个自定义 Select 组件,虽然组件功能和细节可能还有些粗糙,但已能满足基础使用需求。下面我会记录该组件的完整使用教程,也欢迎大家在评论区交流优化思路。如果这份内容能够帮助到你,非常荣幸

原生鸿蒙<select>组件存在两个限制:

  1. 无法自定义下拉箭头图标
  2. 无法灵活控制文本样式
  3. 箭头图标固定:下拉箭头是系统自带的,没法替换成设计稿里的自定义图标,视觉统一性差;

通过自定义组件MenuBuilde 完美解决这些问题,实现效果如下

修改前原生组件:
在这里插入图片描述

修改后效果:在这里插入图片描述


核心代码解析
@Preview
@Component
export struct MenuBuilder {
  // 关键属性定义
  @Prop img0: string = ''  // 默认箭头图标路径
  @Prop img1: string = ''  // 激活状态箭头图标路径
  @Prop menuItermList: string[] = ['']  // 选项数据源
  @Prop selectedValue: string = '请选择' // 默认提示文本
  
  // 状态管理
  @State private isMenuVisible: boolean = false
  @State private ischoose: boolean = false
  @State selectedID: number = -1
  
  // 回调函数
  private returnToSelection?: (value: string) => void
  
  build() {
    Row({ space: 10 }) {
      // 动态文本样式
      Text(this.selectedValue)
        .fontColor(!this.ischoose ? '#dcdcdc' : Color.Black)
      
      // 动态切换箭头图标
      if (this.ischoose) {
        Image(this.isMenuVisible ? $r(this.img0) : $r(this.img1))
          .size({ width: '20vp', height: '20vp' })
          .fillColor(Color.Black)  // 已选择状态着色
      } else {
        Image(this.isMenuVisible ? $r(this.img0) : $r(this.img1))
          .size({ width: '20vp', height: '20vp' })
      }
    }
    // 菜单绑定与事件处理
    .bindMenu(this.MenuBuilder(this.menuItermList), {
      onAppear: () => this.isMenuVisible = true,
      onDisappear: () => this.isMenuVisible = false
    })
    .onClick(() => this.isMenuVisible = !this.isMenuVisible)
  }

  // 菜单构建器
  @Builder
  MenuBuilder(itemList: string[]) {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
      ForEach(itemList, (item: string, index) => {
        Row() {
          Text(item)
            .layoutConfig({ width: '100%', height: 32 })
            .textStyle({ 
              weight: 400, 
              size: 14, 
              color: Color.Black, 
              align: TextAlign.Center 
            })
        }
        // 选中项高亮
        .backgroundColor(this.selectedID == index ? '#f1f4f9' : Color.White)
        .borderRadius(10)
        .onClick(() => {
          this.selectedID = index
          this.ischoose = true
          this.selectedValue = item
          this.returnToSelection?.(item)  // 执行回调
        })
        
        // 添加分隔线
        if (index != itemList.length - 1) {
          Divider().height(10).width('80%').color('#ccc')
        }
      })
    }
    .width(100)  // 菜单宽度控制
  }
}

四大核心功能
  1. 动态图标系统

    • 通过img0/img1属性注入自定义图标资源
    • 根据isMenuVisible状态自动切换图标
      示例代码
    Image(this.isMenuVisible ? $r(this.img0) : $r(this.img1))
    
  2. 智能状态管理

    • ischoose标记选择状态
    • selectedID记录当前选中项索引
    • isMenuVisible控制菜单显隐
  3. 视觉反馈优化

    • 未选择时文本置灰 (#dcdcdc)
    • 选中项背景高亮 (#f1f4f9)
    • 图标点击后黑色填充 (fillColor)
  4. 数据驱动架构

    • 通过menuItermList传入选项数组
    • 使用ForEach动态生成菜单项

使用教程

步骤1:导入组件

import { MenuBuilde } from './MenuBuilde'

步骤2:配置参数

@Entry
@Component
struct Example {
  @State currentVal: string = "苹果"
  private options: string[] = ["苹果", "香蕉", "橙子"]

  build() {
    Column() {
      MenuBuilde({
        img0: "app.media.arrow_up",  // 自定义向上箭头
        img1: "app.media.arrow_down",// 自定义向下箭头
        menuItermList: this.options,
        selectedValue: this.currentVal
      })
      .onSelectionChange((val) => this.currentVal = val) // 回调绑定
    }
  }
}

参数说明表

参数名 类型 必填 说明
img0 string 默认状态图标路径
img1 string 激活状态图标路径
menuItermList string[] 选项文本数组
selectedValue string 初始选中项(默认"请选择")

扩展建议
  1. 增加图标动画
    onClick中添加旋转动画:

    .onClick(() => {
      animateTo({ duration: 200 }, () => {
        this.rotateAngle = this.isMenuVisible ? 180 : 0
      })
    })
    
  2. 支持图标尺寸参数化
    新增@Prop iconSize: number = 20属性
    替换写死的20vp尺寸值

  3. 多语言适配
    selectedValue绑定资源文件:

    @Prop selectedValue: Resource = $r('app.string.please_select')
    

效果对比
特性 原生Select 自定义MenuBuilde
图标自定义 ✔️
文本样式控制 ✔️
选中态反馈 基础实现 高亮动画
回调灵活性 有限 完全可控

源码获取gitee实际项目中打开即可使用

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐