当前位置: 首页 > article >正文

HarmonyOS NEXT - picker 选择器( 包含 单列、多列、底部选择器)

demo 地址: https://github.com/iotjin/JhHarmonyDemo
组件对应代码实现地址
代码不定时更新,请前往github查看最新代码

在demo中这些组件和工具类都通过module实现了,具体可以参考HarmonyOS NEXT - 通过 module 模块化引用公共组件和utils

HarmonyOS NEXT - picker 选择器(包含 单列、多列、底部选择器)

  • 效果图
  • 调用方式
  • JhPickerTool.ets 完整代码

官方dialog 比较反人类,调用比较麻烦,下面两种还略微好点

  • 通过promptAction.openCustomDialog 实现自定义弹窗。对应官方文档
  • 不依赖UI组件的全局自定义弹出框 (openCustomDialog)(推荐)对应官方文档

在三方库上找了一个弹框库,简单调整样式封装了一层

三方库地址:
@pura/harmony-dialog(V1.0.7)

需要先在项目中导入三方库

 ohpm i @pura/harmony-dialog@1.0.7

OpenHarmony ohpm 环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包

!!!注意: 这个组件和JhDialog.ets 使用的同一配置,初始化使用Jhdialog 的初始化就可以了

下面是Jhdialog 使用的文章地址:
HarmonyOS NEXT - Dialog 和完全自定义弹框

效果图

在这里插入图片描述在这里插入图片描述-
在这里插入图片描述在这里插入图片描述在这里插入图片描述

调用方式

需要先全局初始化一次,否则弹框不显示
全局初始化可以放在入口的page处
1.0.8开始需要在在windowStage.loadContent 后执行初始化

以下是在第一个page的aboutToAppear方法初始化的

  aboutToAppear() {
    // 初始化Loading
    let uiContext: UIContext = this.getUIContext();
    JhDialog.initConfig(uiContext)
  }
  • BottomSheet-不带标题
   JhPickerTool.showBottomSheet({
     data: ['hello', 'world', '123'],
     clickCallback: (index, text) => {
       console.error('index', index)
       console.error('text', text)
       JhProgressHUD.showToast(text)
     }
   })
  • BottomSheet-带标题
   JhPickerTool.showBottomSheet({
     title: '请选择',
     data: ['hello', 'world', '123'],
     clickCallback: (index, text) => {
       console.error('index', index)
       console.error('text', text)
       JhProgressHUD.showToast(text)
     }
   })
  • BottomSheet-红色按钮
  JhPickerTool.showBottomSheet({
      title: '请选择操作',
      data: [{
        value: "保存本地",
        fontSize: 18
      }, {
        value: "删除",
        fontColor: Color.Red,
        fontSize: 18
      }],
      clickCallback: (index, text) => {
        console.error('index', index)
        console.error('text', text)
        JhProgressHUD.showToast(text)
      }
    })
  • JhPickerTool-单列(字符串数组)
	  const stringArr = ['11', '22', '33', '44']

      JhPickerTool.showStringPicker({
        data: stringArr,
        title: '请选择类型',
        selectIndex: 1,
        onCancel: () => {
          console.error(`点击了取消按钮`)
        },
        onConfirm: (selectValue, selectIndex: Number) => {
          console.error(`点击了确认按钮`)
          console.error('selectValue:', selectValue)
          console.error('selectIndex:', selectIndex)
          JhProgressHUD.showToast(selectValue.toString())
        },
      })
  • JhPickerTool-单列(对象数组)
	const dictArr: ItemType[] = [
	  { 'label': '类型一', 'value': '1' },
	  { 'label': '类型二', 'value': '2' },
	  { 'label': '类型三', 'value': '3' },
	]

   JhPickerTool.showStringPicker({
     data: dictArr,
     title: '请选择',
     labelKey: 'label',
     selectIndex: 2,
     onCancel: () => {
       console.error(`点击了取消按钮`)
     },
     onConfirm: (selectValue, selectIndex: Number) => {
       console.error(`点击了确认按钮`)
       console.error('selectValue:', JSON.stringify(selectValue))
       console.error('selectValue-label:', selectValue['label'])
       console.error('selectIndex:', selectIndex)
       JhProgressHUD.showToast(JSON.stringify(selectValue))
     },
   })
  • JhPickerTool-两列(对象数组)
		const dictArr2: ItemType[][] = [
		  [
		    { 'label': '大类一', 'value': '1' },
		    { 'label': '大类二', 'value': '2' },
		    { 'label': '大类三', 'value': '3' },
		  ],
		  [
		    { 'label': '小类一', 'value': '11' },
		    { 'label': '小类二', 'value': '22' },
		  ],
		]

     JhPickerTool.showArrayPicker({
       data: dictArr2,
       title: '请选择',
       selectIndex: [1, 1],
       labelKey: 'label',
       onCancel: () => {
         console.error(`点击了取消按钮`)
       },
       onConfirm: (selectItemArr, selectIndexArr: Number[]) => {
         console.error(`点击了确认按钮`)
         console.error('selectItemArr:', JSON.stringify(selectItemArr))
         console.error('selectIndexArr:', JSON.stringify(selectIndexArr))
         JhProgressHUD.showToast(JSON.stringify(selectItemArr))
       },
     })
  • JhPickerTool-三列(对象数组)
	const dictArr3: ItemType[][] = [
	  [
	    { 'label': '大类一', 'value': '1' },
	    { 'label': '大类二', 'value': '2' },
	    { 'label': '大类三', 'value': '3' },
	  ],
	  [
	    { 'label': '中类一', 'value': '1' },
	    { 'label': '中型二', 'value': '2' },
	    { 'label': '中型三', 'value': '3' },
	    { 'label': '中型四', 'value': '4' },
	  ],
	  [
	    { 'label': '小类一', 'value': '1' },
	    { 'label': '小类二', 'value': '2' },
	  ],
	]

    JhPickerTool.showArrayPicker({
      data: dictArr3,
      title: '请选择',
      selectIndex: [1, 2, 1],
      labelKey: 'label',
      onCancel: () => {
        console.error(`点击了取消按钮`)
      },
      onConfirm: (selectItemArr, selectIndexArr: Number[]) => {
        console.error(`点击了确认按钮`)
        console.error('selectItemArr:', JSON.stringify(selectItemArr))
        console.error('selectIndexArr:', JSON.stringify(selectIndexArr))
        JhProgressHUD.showToast(JSON.stringify(selectItemArr))
      },
    })

JhPickerTool.ets 完整代码

///  JhPickerTool.ets
///
///  Created by iotjin on 2024/12/25. 
///  description:  @pura/harmony-dialog 封装。JhDialog、JhToast、JhPickerTool共用同一默认配置

import { SheetOptions, DialogAction, DialogHelper, OnActionCallBack } from "@pura/harmony-dialog"
import { KColors } from "../configs/Colors"


const _labelKey = 'label' // 对象数组的文字字段
const _titleText = '请选择'
const _cancelText = '取消'
const _confirmText = '确认'

const _kTitleFontSize = 18.0
const _kBtnFontSize = 17.0
const _textFontSize = 18.0
const _selectTextFontSize = 20.0
const _kHeaderRadius = 10.0

const _bgColor = KColors.kPickerBgColor
const _titleColor = KColors.kPickerTitleColor
const _btnColor = KColors.kPickerBtnColor
// const  _headerColor = '#E6E6E6'
const _headerColor = KColors.kPickerHeaderColor
const _selectTextColor = KColors.kPickerTextColor
const _otherTextColor = KColors.kLightGreyTextColor

export interface JhPickerOptions {
  data?: ESObject[] // 数据源
  labelKey?: string, // 对象数组的文字字段, 默认_labelKey
  selectIndex?: number | number[]
  title?: ResourceStr
  leftText?: ResourceStr
  rightText?: ResourceStr
  onCancel?: () => void
  /// 选择回调
  /// 单列选择器返回选中行对象和index
  /// 多列选择器返回选中行对象数组和index数组
  onConfirm?: (selectValue: string | string[], selectIndexArr: ESObject) => void
}

export interface JhBottomSheetOptions {
  data?: Array<SheetOptions> | Array<ResourceStr>; // 数据源
  title?: ResourceStr
  /// 选择回调
  /// index 从上往下 0,1,2
  clickCallback?: (selectIndex: number, selectText: string) => void
}

export class JhPickerTool {
  /**
   * 底部弹框
   * @param options
   */
  public static showBottomSheet(options: JhBottomSheetOptions) {
    if ((options.data ?? []).length == 0) {
      return
    }
    DialogHelper.showBottomSheetDialog({
      title: options.title ?? '',
      titleFontColor: _titleColor,
      cancelValue: _cancelText,
      sheets: options.data ?? [],
      cornerRadius: _kHeaderRadius,
      backgroundColor: _bgColor,
      autoCancel: true, // 点击遮障层时,是否关闭弹窗,true表示关闭弹窗。默认关闭
      backCancel: false, // 点击返回键或手势返回时,是否关闭弹窗;实现onWillDismiss函数时,该参数不起作用。默认不关闭
      actionCancel: true, // 点击操作按钮时,是否关闭弹窗。false表示不关闭弹窗。
      onAction: (index) => {
        const isStringArray = JhPickerTool.isOneStringArray(options.data)
        const selectedText: string = isStringArray ? options.data![index] : options.data![index]['value']
        options.clickCallback?.(index, selectedText)
      }
    })
  }

  /**
   * 单列选择器
   * 单列选择器返回选中行对象和index
   * @param options
   */
  public static showStringPicker(options: JhPickerOptions) {
    const originalList: ESObject[] = options.data ?? []
    if (originalList.length == 0 || !JhPickerTool.isOneDimensionalArray(originalList)) {
      return
    }
    const isStringArray = JhPickerTool.isOneStringArray(originalList)
    const labelKey = options.labelKey ?? _labelKey
    const tempList: string[] = originalList.map((item: ESObject) => {
      return (isStringArray ? item : item[labelKey]) as string
    })

    DialogHelper.showTextPickerDialog({
      range: tempList,
      value: tempList[options.selectIndex as number ?? 0],
      title: options.title ?? _titleText,
      titleFontColor: _titleColor,
      titleBackground: _headerColor,
      primaryButton: {
        value: options.leftText ?? _cancelText,
        fontColor: _btnColor,
      },
      secondaryButton: {
        value: options.rightText ?? _confirmText,
        fontColor: _btnColor,
      },
      //设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
      disappearTextStyle: { color: _otherTextColor, font: { size: _textFontSize } },
      //设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。
      textStyle: { color: _otherTextColor, font: { size: _textFontSize } },
      //设置选中项的文本颜色、字号、字体粗细。
      selectedTextStyle: { color: _selectTextColor, font: { size: _selectTextFontSize } },
      cornerRadius: _kHeaderRadius,
      backgroundColor: _bgColor,
      canLoop: false,
      autoCancel: true, // 点击遮障层时,是否关闭弹窗,true表示关闭弹窗。默认关闭
      backCancel: false, // 点击返回键或手势返回时,是否关闭弹窗;实现onWillDismiss函数时,该参数不起作用。默认不关闭
      actionCancel: true, // 点击操作按钮时,是否关闭弹窗。false表示不关闭弹窗。
      onChange: (value: string | string[], index: number | number[]): void => {
        // console.log(`value: ${value}`)
        // console.log(`index: ${index}`)
      },
      onAction: (action: number, dialogId: string, value: string | string[]) => {
        if (action == DialogAction.ONE) {
          options.onCancel?.()
        } else {
          if (isStringArray) {
            const foundIndex = tempList.findIndex((item) => item === value)
            const selectIndex = foundIndex === -1 ? 0 : foundIndex
            options.onConfirm?.(value, selectIndex)
          } else {
            const foundIndex = originalList.findIndex((item: ESObject) => item[labelKey] === value)
            const selectIndex = foundIndex === -1 ? 0 : foundIndex
            options.onConfirm?.(originalList[selectIndex], selectIndex)
          }
        }
      }
    })
  }

  /**
   * 多列选择器
   * 多列选择器返回选中行对象数组和index数组
   * @param options
   */
  public static showArrayPicker(options: JhPickerOptions) {
    const originalList: ESObject[] = options.data ?? []
    if (originalList.length == 0 || JhPickerTool.isOneDimensionalArray(originalList)) {
      return
    }
    const isMultiStringArray = JhPickerTool.isMultiStringArray(originalList)
    const labelKey = options.labelKey ?? _labelKey

    let tempList: string[][] = originalList
    if (!isMultiStringArray) {
      const labelArr: string[][] = originalList.map((subArray: ESObject) => {
        return subArray.map((item: ESObject) => item[labelKey] as string) as string[]
      })
      tempList = labelArr
    }

    let valueList: string[] = []
    if (options.selectIndex && Array.isArray(options.selectIndex)) {
      for (let i = 0; i < options.selectIndex!.length; i++) {
        let columnData: ESObject = originalList[i]
        const index = options.selectIndex![i]
        if (index >= 0 && index < columnData.length) {
          valueList.push(isMultiStringArray ? columnData[index] : columnData[index][labelKey])
        } else {
          valueList.push(isMultiStringArray ? columnData[0] : columnData[0][labelKey])
        }
      }
    }
    DialogHelper.showTextPickerDialog({
      range: tempList,
      value: valueList,
      title: options.title ?? _titleText,
      titleFontColor: _titleColor,
      titleBackground: _headerColor,
      primaryButton: {
        value: options.leftText ?? _cancelText,
        fontColor: _btnColor,
      },
      secondaryButton: {
        value: options.rightText ?? _confirmText,
        fontColor: _btnColor,
      },
      //设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
      disappearTextStyle: { color: _otherTextColor, font: { size: _textFontSize } },
      //设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。
      textStyle: { color: _otherTextColor, font: { size: _textFontSize } },
      //设置选中项的文本颜色、字号、字体粗细。
      selectedTextStyle: { color: _selectTextColor, font: { size: _selectTextFontSize } },
      cornerRadius: _kHeaderRadius,
      backgroundColor: _bgColor,
      canLoop: false,
      autoCancel: true, // 点击遮障层时,是否关闭弹窗,true表示关闭弹窗。默认关闭
      backCancel: false, // 点击返回键或手势返回时,是否关闭弹窗;实现onWillDismiss函数时,该参数不起作用。默认不关闭
      actionCancel: true, // 点击操作按钮时,是否关闭弹窗。false表示不关闭弹窗。
      onChange: (value: string | string[], index: number | number[]): void => {
        // console.log(`value: ${value}`)
        // console.log(`index: ${index}`)
      },
      onAction: (action: number, dialogId: string, values: string | string[]) => {
        if (action == DialogAction.ONE) {
          options.onCancel?.()
        } else {
          if (Array.isArray(values)) {
            let selectItemArr: ESObject = []
            let selectIndexArr: number[] = []
            for (let i = 0; i < values.length; i++) {
              let columnData: ESObject = originalList[i]
              const value = values[i]
              const foundIndex: number = columnData.findIndex((item: ESObject) => (isMultiStringArray ? item : item[labelKey]) === value)
              const selectIndex = foundIndex === -1 ? 0 : foundIndex
              selectIndexArr.push(selectIndex)
              selectItemArr.push(columnData[selectIndex])
            }
            options.onConfirm?.(selectItemArr, selectIndexArr)
          }
        }
      }
    })
  }

  /**
   * 是否是一维数组
   * @param arr
   * @returns
   */
  public static isOneDimensionalArray(arr: ESObject[]) {
    // 检查是否为数组,并且数组内元素不是数组, 使用 some 方法检查是否有任何元素是数组,如果存在,则说明是非一维数组
    return Array.isArray(arr) && !arr.some((item: ESObject) => Array.isArray(item))
  }

  /**
   * 是否是一维字符串数组
   * @param arr
   * @returns
   */
  public static isOneStringArray(arr: ESObject[]) {
    return Array.isArray(arr) && arr.every((item: ESObject) => typeof item === 'string')
  }

  /**
   * 是否是多维字符串数组
   * @param arr
   * @returns
   */
  public static isMultiStringArray(arr: ESObject[]) {
    // 如果不是数组,直接返回 false
    if (!Array.isArray(arr)) {
      return false
    }
    // 检查数组中的每个元素是否是字符串数组
    return arr.every((item: ESObject): boolean => JhPickerTool.isOneStringArray(item))
  }
}

http://www.kler.cn/a/542324.html

相关文章:

  • deepseek+kimi一键生成PPT
  • Docker 部署 MySQL-5.7 单机版
  • 推荐一款 免费的SSL,自动续期
  • 81页精品PPT | 华为流程与信息化实践与架构规划分享
  • Python Pandas(3):DataFrame
  • Django操作指令大集合说明
  • Django学习笔记(第一天:Django基本知识简介与启动)
  • C++性能优化—人工底稿版
  • Ubuntu 下 nginx-1.24.0 源码分析 ngx_tm_t 类型
  • Node.js怎么调用到打包的python文件呢
  • 支持高并发的 Web 应用系统架构中LVS和keepalived是什么?
  • RabbitMQ 如何设置限流?
  • 安卓基础(Intent)
  • 运用 LangChain 编排任务处理流水线,实现多轮对话场景
  • 【C语言标准库函数】标准输入输出函数详解[4]:二进制文件读写函数
  • 通用的将jar制作成docker镜像sh脚本
  • 机器学习 - 数据的特征表示
  • 《Transformer架构完全解析:从零开始读懂深度学习的革命性模型》
  • 【C++指南】解锁C++ STL:从入门到进阶的技术之旅
  • LabVIEW 开发航天项目软件
  • SSM开发(十一) mybatis关联关系多表查询(嵌套查询,举例说明)
  • unity碰撞的监测和监听
  • SpringBoot 项目中使用Log4j2详细(避坑)
  • 在Uniapp中使用阿里云OSS插件实现文件上传
  • 高级java每日一道面试题-2025年02月03日-服务器篇[Nginx篇]-Nginx是如何处理一个HTTP请求的呢 ?
  • 【leetcode】滑动窗口刷题总结