⭐本期内容:【HarmonyOS4+NEXT】Slider组件详解与实战
🏆系列专栏:鸿蒙HarmonyOS4+NEXT:探索未来智能生态新纪元
文章目录
前言
Slider是HarmonyOS的ArkUI框架中提供的一个基础交互组件,主要用于在连续或离散的区间内进行数值选择。在日常应用中,Slider常被用于音量调节、亮度调整、视频进度条等场景,为用户提供直观的交互体验。
Slider组件基本属性
基础属性
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
value | 当前进度值 | number | 0 |
min | 最小值 | number | 0 |
max | 最大值 | number | 100 |
step | 步长,取值必须大于0 | number | 1 |
style | 滑块样式,分为OutSet和InSet | SliderStyle | SliderStyle.OutSet |
showTips | 是否显示提示 | boolean | false |
showSteps | 是否显示步长刻度 | boolean | false |
外观属性
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
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')
}
}
总结
今日学习之旅已圆满收笔,愿每位君子都满载而归,心有所悟!🤩
若你对这探索之旅情有独钟,何不紧随此专栏的步伐?新知如潮,连绵不绝,将与你共绘思维的绚烂篇章,舞动智慧的火花!😎
轻轻一点下方名片,加入我们的粉丝大家庭,让我们在知识的浩瀚海洋中再次相逢,携手见证智慧之花的绚丽绽放,共享求知的喜悦与盛宴!👍