【HarmonyOS4+NEXT】Slider组件详解与实战

#新星杯·14天创作挑战营·第10期#

在这里插入图片描述

⭐本期内容:【HarmonyOS4+NEXT】Slider组件详解与实战
🏆系列专栏:鸿蒙HarmonyOS4+NEXT:探索未来智能生态新纪元



前言

Slider是HarmonyOS的ArkUI框架中提供的一个基础交互组件,主要用于在连续或离散的区间内进行数值选择。在日常应用中,Slider常被用于音量调节、亮度调整、视频进度条等场景,为用户提供直观的交互体验。


Slider组件基本属性

基础属性

属性说明类型默认值
value当前进度值number0
min最小值number0
max最大值number100
step步长,取值必须大于0number1
style滑块样式,分为OutSet和InSetSliderStyleSliderStyle.OutSet
showTips是否显示提示booleanfalse
showSteps是否显示步长刻度booleanfalse

外观属性

属性说明类型默认值
blockColor滑块颜色Color-
trackColor滑动条背景颜色Color-
selectedColor已选择部分的颜色Color-
trackThickness滑动条宽度Length-
blockSize滑块大小,通过宽高设置{width: Length, height: Length}-
trackBorderRadius滑动条圆角半径Length-

事件属性

属性说明回调参数
onChange滑块位置发生变化时触发(value: number, mode: SliderChangeMode) => void

其中,SliderChangeMode有以下几种值:

  • Begin:开始位置变化
  • Moving:正在移动中
  • End:结束位置变化

基本用法

创建简单的Slider组件

如下,是Slider组件的基本用法,构建一个垂直布局的界面,顶部显示当前滑块值的文本,下方是一个可交互的滑动条。通过==@State装饰的响应式变量sliderValue==追踪并显示滑块位置,用户拖动滑块时,onChange事件触发更新显示值。

// @Entry装饰器标识这是一个页面入口组件
// @Component装饰器声明这是一个自定义组件
// @State sliderValue: number = 50定义了一个响应式状态变量,初始值为50,用于存储和更新滑块的当前值
@Entry
@Component
struct SliderExample {
  @State sliderValue: number = 50;

  build() {
    Column({ space: 20 }) {
      Text(`当前值: ${this.sliderValue.toFixed(0)}`)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Slider({
        value: this.sliderValue,
        min: 0,
        max: 100,
        step: 1
      })
        .width('90%')
        .blockColor('#ff366ef1')
        .trackThickness(7)
        .showTips(true)
        .onChange((value: number) => {
          this.sliderValue = value;
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

在这里插入图片描述

通过Slider控制图片大小

Slider可以实现交互式图片尺寸调整功能。通过@State声明的imageWidth变量控制图片宽度,用户可以通过三种方式调整图片大小,拖动Slider滑块在100-300px范围内以10px为步长调整,点击"缩小"或"放大"按钮分别减少或增加10px宽度,并在界面上实时显示当前图片宽度,图片使用插值算法保证放大缩小时的显示效果。

@Entry
@Component
struct ImageResizeSlider {
  @State imageWidth: number = 150;

  build() {
    Column({ space: 20 }) {
      Image($r('app.media.app_icon'))
        .width(this.imageWidth)
        .interpolation(ImageInterpolation.High)

      Text(`图片宽度: ${this.imageWidth.toFixed(0)}px`)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Row({ space: 20 }) {
        Button('缩小')
          .width(80)
          .fontSize(20)
          .onClick(() => {
            if (this.imageWidth >= 10) {
              this.imageWidth -= 10;
            }
          })

        Button('放大')
          .width(80)
          .fontSize(20)
          .onClick(() => {
            if (this.imageWidth < 300) {
              this.imageWidth += 10;
            }
          })
      }

      Slider({
        min: 100,
        max: 300,
        value: this.imageWidth,
        step: 10
      })
        .width('90%')
        .blockColor('#ff7238c6')
        .trackThickness(7)
        .showTips(true)
        .onChange(value => {
          this.imageWidth = value;
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

在这里插入图片描述

自定义Slider样式

在HarmonyOS中,可以通过多种方式自定义Slider的外观。如下,通过Stack布局叠加实现了两种不同风格的滑动条:一个是带"+“和”-"控制按钮的内嵌式滑动条(使用SliderStyle.InSet样式),按钮通过zIndex提升层级并设置透明触摸行为(hitTestBehavior)使手势能穿透到下层Slider;另一个是纯橙色轨道的圆角进度条,通过设置selectedColor为透明(‘rgba(0, 0, 0, 0)’)并配置粗轨道(trackThickness为66)实现效果,整体布局采用Column纵向排列这两种自定义样式的滑动条展示。

@Entry
@Component
struct SliderDemo {
  @State sliderValue: number = 60;

  build() {
    Column() {
      Text('自定义渐变Slider').fontSize(16).fontColor('#51CBE0').width('90%').margin(15)
      Stack() {
        Row() {
          Slider({
            value: this.sliderValue,
            min: 0,
            max: 100,
            style: SliderStyle.InSet
          })
            .blockColor('#FFFFFF')
            .trackColor('#EBEBEB')
            .trackThickness(66)
            .selectedColor('#D9D9D9')
            .onChange((value: number) => {
              this.sliderValue = value;
              console.info('value:' + value);
            })
        }.width('100%')

        Row() {
          Text("-").fontSize(30).fontWeight(FontWeight.Bold)
            .width(55).height(55)
          Text("+").fontSize(30).fontWeight(FontWeight.Bold)
            .width(55).height(55)
        }
        .zIndex(1)
        .width('90%')
        .justifyContent(FlexAlign.SpaceBetween)
        .hitTestBehavior(HitTestMode.Transparent)
      }

      Text('圆角纯色进度条').fontSize(16).fontColor('#51CBE0').width('90%').margin(25)
      Row() {
        Slider({
          min: 0,
          max: 100,
          value: 40,
          style: SliderStyle.InSet
        })
          .selectedColor('rgba(0, 0, 0, 0)')
          .trackThickness(66)
          .trackColor('#FFAB5B')
      }.width('90%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#c9ffffff')
  }
}

在这里插入图片描述

视频进度条缓冲区的实现

slider可以实现视频播放器进度条。
通过Stack叠加布局创建双层效果:底层使用Progress组件(设置灰色填充色和浅灰背景色)显示视频的缓冲进度,上层使用Slider组件(设置橙色选中区域和透明轨道)展示当前播放进度;程序在初始化时通过display模块获取屏幕实际宽度并转换为视图单位,同时为Progress组件宽度减去24单位来匹配Slider的默认边距,确保两个组件视觉对齐,从而呈现出既能显示播放进度又能展示缓冲状态的视频控制条。

import display from '@ohos.display'; // 添加display模块导入

@Entry // 添加Entry装饰器,因为页面必须有一个Entry
@Component
export struct VideoSliderExample {
  @State displayScreenWidth: number = 375; // 默认宽度,避免初始值为0
  @State playProgress: number = 20;
  @State bufferProgress: number = 70;

  aboutToAppear() {
    // 获取屏幕宽度
    try {
      let displayClass = display.getDefaultDisplaySync();
      if (displayClass && displayClass.width) {
        this.displayScreenWidth = px2vp(displayClass.width);
      }
    } catch (err) {
      console.error('Failed to get display: ' + JSON.stringify(err));
      // 使用默认值
    }
  }

  build() {
    Column() {
      Stack() {
        Progress({ value: this.bufferProgress, type: ProgressType.Linear })
          // 设置缓冲区颜色
          .color('#D9D9D9')
          .backgroundColor('#EBEBEB')
          .style({
            strokeWidth: 4
          })
            // 左右各减去24的Slider避让距离
          .width(this.displayScreenWidth - 24)

        Slider({
          style: SliderStyle.OutSet,
          value: this.playProgress
        })
          .trackColor('rgba(0,0,0,0)')
          .selectedColor('#F29200')
          .width(this.displayScreenWidth)
          .onChange((value) => {
            this.playProgress = value;
          })
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#ffffff')
  }
}

在这里插入图片描述

增大Slider的触摸响应区

为了提升用户体验,特别是在视频播放器等应用中,可以通过responseRegion属性来增大Slider的触摸响应区域
如下,实现了增强触摸区域的滑动条
通过Stack布局创建了三层重叠元素:中间为实际Slider组件,上下分别添加了橙色和粉色触摸响应区域;关键技术是使用responseRegion属性扩展了触摸热区(向上、当前和向下各一个区域),并配合hitTestBehavior和PanGesture实现了在扩展区域内的滑动控制;当用户在任何这些区域滑动时,都会触发状态更新并改变滑块位置和显示文本,大大提升了触摸操作的便捷性,特别适合视频播放器等需要精确但又便于操作的场景。

@Entry // 添加Entry装饰器
@Component
export struct IncreaseTouchAreaSliderExample {
  @State sliderValue: number = 40;
  @State statusText: string = '拖动下方滑块';
  flagValue: number = 0;

  build() {
    Stack() {
      Text(this.statusText).fontSize(20)

      // 上方触摸区
      Row() {
      }
      .backgroundColor(Color.Orange)
      .width('100%')
      .height(24)
      .position({ x: 0, y: '100%' })
      .markAnchor({ x: 0, y: 96 })

      // 下方触摸区
      Row() {
      }
      .backgroundColor(Color.Pink)
      .width('100%')
      .height(24)
      .position({ x: 0, y: '100%' })
      .markAnchor({ x: 0, y: 48 })

      // Slider区域
      Row() {
        Slider({
          style: SliderStyle.OutSet,
          value: this.sliderValue
        })
          // 移除不支持的属性
          // .blockSize和.blockBorderWidth属性不存在,已移除
          .height(24)
          .trackThickness(3)
          .backgroundColor(Color.Red)
          .onChange((value) => {
            this.sliderValue = value;
            this.statusText = `当前值: ${value.toFixed(0)}`;
          })
      }
      .position({ x: 0, y: '100%' })
      .markAnchor({ x: 0, y: 72 })
      .backgroundColor('rgba(255, 255, 255, 0.5)')
      // 设置触摸热区
      .responseRegion([
        {
          x: 0,
          y: 0,
          width: '100%',
          height: '100%'
        },
        {
          x: 0,
          y: '100%',
          width: '100%',
          height: '100%'
        },
        {
          x: 0,
          y: '-100%',
          width: '100%',
          height: '100%'
        }
      ])
      .hitTestBehavior(HitTestMode.Transparent)
      .gesture(
        PanGesture(new PanGestureOptions({ direction: PanDirection.Left | PanDirection.Right }))
          .onActionStart(() => {
            this.flagValue = this.sliderValue;
          })
          .onActionUpdate((event?: GestureEvent) => {
            if (event) {
              this.sliderValue = this.flagValue + (event.offsetX / 3);
              this.statusText = `拖动中: ${this.sliderValue.toFixed(0)}`;
            }
          })
      )
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#f0f0f0')
  }
}

在这里插入图片描述


总结

今日学习之旅已圆满收笔,愿每位君子都满载而归,心有所悟!🤩

若你对这探索之旅情有独钟,何不紧随此专栏的步伐?新知如潮,连绵不绝,将与你共绘思维的绚烂篇章,舞动智慧的火花!😎

轻轻一点下方名片,加入我们的粉丝大家庭,让我们在知识的浩瀚海洋中再次相逢,携手见证智慧之花的绚丽绽放,共享求知的喜悦与盛宴!👍
在这里插入图片描述

评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜颜yan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值