Openharmony - 基于ArkUI(TS)开发颜色选择器 原创 精华

中软HOS小鸿
发布于 2022-7-28 10:31
浏览
3收藏

作者:梁青松

项目介绍

本项目基于OpenHarmony的ArkUI框架:TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:基于TS扩展的声明式开发范式,因为OpenHarmony的API相对于HarmonyOS的API,功能上比较完善和成熟的,有些新的技术也早早接触到,所以本项目直接使用OpenHarmony SDK开发。

工具版本: DevEco Studio 3.0 Beta4

SDK版本: 3.1.6.6(API Version 8 Release)

项目功能: 常见的颜色选择器,使用颜色条滑动选择主色调,更改颜色面板的颜色,并触摸选择颜色。

效果演示

Openharmony - 基于ArkUI(TS)开发颜色选择器-鸿蒙开发者社区

主要API

画布组件canvas:画布组件,用于自定义绘制图形。

方法/属性 解释
createLinearGradient() 创建一个线性渐变色
addColorStop() 设置渐变颜色和比例
getImageData() 获取坐标点像素的颜色值
fillRect() 填充一个矩形
clearRect() 清空画布
fillStyle 属性:指定绘制的填充色

实现思路

1. 绘制颜色条

使用createLinearGradient()方法创建一个从上至下的线性渐变色。

代码片段

  /**
   * 颜色条
   */
  @Builder ColorBar() {
    Canvas(this.crcBar)
      .onAreaChange((oldValue: Area, newValue: Area) => {
        // 获取组件的宽高
        this.barWidth = parseInt(newValue.width.toString())
        this.barHeight = parseInt(newValue.height.toString())
        this.barIndicatorSize = this.barWidth / 3
        // 创建渐变色的范围
        const grad = this.crcBar.createLinearGradient(0, 0, 0, this.barHeight)
        // 设置渐变颜色和比例。
        grad.addColorStop(0, 'rgb(255, 0, 0)')
        grad.addColorStop(1 * 1 / 6, 'rgb(255, 255, 0)')
        grad.addColorStop(2 * 1 / 6, 'rgb(0, 255, 0)') 
        grad.addColorStop(3 * 1 / 6, 'rgb(0, 255, 255)')
        grad.addColorStop(4 * 1 / 6, 'rgb(0, 0, 255)')
        grad.addColorStop(5 * 1 / 6, 'rgb(255, 0, 255)')
        grad.addColorStop(1, 'rgb(255, 0, 0)')
        // 设置渐变色
        this.crcBar.fillStyle = grad
        // 绘制矩形
        this.crcBar.fillRect(0, 0, this.barWidth, this.barHeight)
      }).width('100%')
      .borderWidth(0.5)
  }

2. 绘制颜色条指示器

使用 Path绘制组件 :绘制两个相对的三角形,作为颜色条指示器。

代码片段

Openharmony - 基于ArkUI(TS)开发颜色选择器-鸿蒙开发者社区

  /**
   * 颜色条指示器
   */
  @Builder ColorBarIndicator() {
    Row() {
      if (this.barIndicatorSize != 0) {
        Path()
          .width(this.barIndicatorSize)
          .height(this.barIndicatorSize)
          .commands(`M0 0 L${vp2px(this.barIndicatorSize)} ${vp2px(this.barIndicatorSize / 2)} L0 ${vp2px(this.barIndicatorSize)} Z`)
          .fill('#00000000')
          .stroke(Color.Black)
          .strokeWidth(0.8)

        Blank()

        Path()
          .width(this.barIndicatorSize)
          .height(this.barIndicatorSize)
          .commands(`M0 ${vp2px(this.barIndicatorSize / 2)} L${vp2px(this.barIndicatorSize)} 0 L${vp2px(this.barIndicatorSize)} ${vp2px(this.barIndicatorSize)} Z`)
          .fill('#00000000')
          .stroke(Color.Black)
          .strokeWidth(0.8)
      }
    }.width('100%')
    .padding(1)
    .offset({ y: this.barIndicatorOffsetY })
    .markAnchor({ y: '50%' })
  }

3. 颜色条滑动选择颜色

设置颜色条的触摸事件,根据坐标点,调用getImageData()方法获取触摸坐标点像素的颜色值。并更新颜色条指示器的Y轴位置。

代码片段

  /**
   * 颜色条触摸事件
   */
  onTouchEventBar(event: TouchEvent) {
    // x坐标
    let x = event.touches[0].x
    // y坐标
    let y = event.touches[0].y
    // 触摸区域限制
    if (x < 0)x = 0
    if (x > this.barWidth - 1.2) x = this.barWidth - 1.2
    if (y < 1)y = 1
    if (y > this.barHeight - 1.2) y = this.barHeight - 1.2
    console.log(`颜色条-当前坐标:x = ${x}, y = ${y}`)
    // 触摸y坐标赋值给指示器偏移量
    this.barIndicatorOffsetY = y
    // 获取颜色条坐标点一个像素的颜色值
    let imageData = this.crcBar.getImageData(x, y, px2vp(1), px2vp(1))
    console.log(`颜色条-当前颜色:` + JSON.stringify(imageData))
    // 绘制颜色面板
        		   this.drawColorBoard(`rgb(${imageData.data[0]},${imageData.data[1]},${imageData.data[2]})`)
    // 获取颜色面板选中的颜色
    this.getBoardSelectColor()
  }

4. 绘制颜色面板

使用fillRect()绘制背景矩形,在其之上绘制:从左至右,白色–>透明渐变色,最后绘制:从下至上,黑色–>透明渐变色。

  /**
   * 绘制颜色面板
   * @param bgColor 背景颜色 默认颜色:红色
   */
  drawColorBoard(bgColor = 'rgb(255, 0, 0)') {
    // 清空画布
    this.crcBoard.clearRect(0, 0, this.boardWidth, this.boardHeight)

    // 绘制背景色
    this.crcBoard.fillStyle = bgColor
    this.crcBoard.fillRect(0, 0, this.boardWidth, this.boardHeight)

    // 绘制渐变色:白色->透明色
    const gradWhite = this.crcBoard.createLinearGradient(0, 0, this.boardWidth, 0)
    gradWhite.addColorStop(0, 'rgb(255,255,255)')
    gradWhite.addColorStop(1, 'rgba(255,255,255,0)')
    this.crcBoard.fillStyle = gradWhite
    this.crcBoard.fillRect(0, 0, this.boardWidth, this.boardHeight)

    // 绘制渐变色:黑色->透明色
    const gradBlack = this.crcBoard.createLinearGradient(0, this.boardHeight, 0, 0)
    gradBlack.addColorStop(0, 'rgb(0,0,0)')
    gradBlack.addColorStop(1, 'rgba(0,0,0,0)')
    this.crcBoard.fillStyle = gradBlack
    this.crcBoard.fillRect(0, 0, this.boardWidth, this.boardHeight)
  }

5. 绘制颜色面板指示器

这个很简单,就是组件设置边框和圆角,圆角半径为宽高一半为圆形,大圆套小圆

  /**
   * 颜色面板指示器
   */
  @Builder ColorBoardIndicator() {
    if (this.boardIndicatorSize != 0) {
      Stack() {
        Stack() {
        }
        .width(this.boardIndicatorSize - 1)
        .height(this.boardIndicatorSize - 1)
        .border({ color: Color.White, width: 1, radius: this.boardIndicatorSize / 2 })

        Stack() {
        }
        .width(this.boardIndicatorSize)
        .height(this.boardIndicatorSize)
        .border({ color: Color.Black, width: 1, radius: this.boardIndicatorSize / 2 })
      }.offset({ x: this.boardIndicatorOffsetX, y: this.boardIndicatorOffsetY })
      .markAnchor({ x: '50%', y: '50%' })
    }
  }

6. 颜色面板触摸选择颜色

设置颜色条的触摸事件,根据坐标点,调用getImageData()方法获取触摸坐标点像素的颜色值。并更新颜色面板指示器的的XY位置。(代码片段)

  /**
   * 颜色面板触摸事件
   */
  onTouchEventBoard(event: TouchEvent) {
    // x坐标
    let x = event.touches[0].x
    // y坐标
    let y = event.touches[0].y
    // 触摸区域限制
    if (x < 0)x = 0
    if (x > this.boardWidth - 1) x = this.boardWidth - 1
    if (y < 0)y = 0
    if (y > this.boardHeight - 1) y = this.boardHeight - 1
    // 触摸xy坐标赋值给指示器偏移量
    this.boardIndicatorOffsetX = x
    this.boardIndicatorOffsetY = y
    // 获取颜色面板选中的颜色
    this.getBoardSelectColor()
  }
  /**
   * 获取颜色面板选中的颜色
   */
  getBoardSelectColor() {
    console.log(`颜色面板-当前坐标:x = ${this.boardIndicatorOffsetX}, y = ${this.boardIndicatorOffsetY}`)
    // 获取坐标点一个像素的颜色值
    let imageData = this.crcBoard.getImageData(this.boardIndicatorOffsetX, this.boardIndicatorOffsetY, px2vp(1), px2vp(1))
    console.log(`颜色面板-当前颜色:` + JSON.stringify(imageData))
    this.colorChange(`rgb(${imageData.data[0]},${imageData.data[1]},${imageData.data[2]})`)
  }

7. 外部调用

界面加载成功后,ColorPickerView组件提供一个方法回调。直接在回调中获取颜色变化。来更新数据。

import { ColorPickerView } from '../component/ColorPicker'

@Entry
@Component
struct Index {
  @State color: string = 'rgb(255, 0, 0)'

  build() {
    Column() {
      Text('Hello World') 
        .fontSize(40)
        .fontWeight(FontWeight.Bold)
        .fontColor(this.color)

      Stack() {
        ColorPickerView({
          colorChange: (color) => {
            this.color = color
          }
        })
      }.width(300)
      .height(300)
      .margin({ top: 30 })

    }.width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

总结

本项目没有什么特别难的点,主要还是熟悉API,多看官方文档,多看一些优秀的项目,只有把原理掌握到自己手上才是王道。

每天进步一点点、需要付出努力亿点点。

项目地址: ArkUI(TS)声明式开发:颜色选择器

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
7
收藏 3
回复
举报
4条回复
按时间正序
/
按时间倒序
只有敬亭山
只有敬亭山

佩服大佬!!!

回复
2022-7-28 14:08:07
红叶亦知秋
红叶亦知秋

熟悉API,多看官方文档,多看一些优秀的项目+ 亿点点努力 = 成为大佬

回复
2022-7-28 14:20:44
82王先生
82王先生

sixisixsix

回复
2022-7-28 15:02:22
lollipoptt
lollipoptt

牛啊牛啊

回复
2022-7-28 15:05:07
回复
    相关推荐