自定义组件—基于Slider实现时间滑动组件 原创

在敲键盘的小鱼干很饥饿
发布于 2024-12-30 17:17
浏览
0收藏

1. 演示效果

自定义组件—基于Slider实现时间滑动组件-鸿蒙开发者社区

2. 引言

本篇要介绍的是一个用于管理用户在不同地点驻留时间的一个强大的时间选择组件,以便用户能够方便地设置和调整驻留时间。现有的Slider组件虽然功能强大,但在我们的项目中无法直接满足同时选择小时和分钟的需求。因此,我们决定自定义一个基于Slider组件的时间滑动条,以提供更精确和灵活的时间选择功能,并且还实现了响应式布局来调整组件的大小,然后就可以使用这个自定义组件进行使用,如半模态弹窗,可以见我的这一篇博客就是以这个组件为例子自定义组件+半模态弹窗当然也可以封装成普通弹窗我的响应式布局的另一种就是弹窗,这里就不做介绍了。

3. Slider组件介绍

滑动条组件(Slider)通常用于快速调节设置值,如音量调节、亮度调节等应用场景。它提供了一个直观的界面,允许用户通过滑动操作在一定范围内选择数值。

3.1. 主要参数说明

  • value:当前进度值。类型:number默认值:与参数min的取值一致。说明:该参数支持双向绑定变量。
  • min:设置最小值。类型:number默认值:0
  • max:设置最大值。类型:number默认值:100说明:若min >= max,则min取默认值0,max取默认值100。value不在[min, max]范围之内,取min或者max,靠近min取min,靠近max取max。
  • step:设置Slider滑动步长。类型:number默认值:1取值范围:[0.01, max - min]
    说明:若设置的step值小于0或大于max值,则按默认值显示。
  • style:设置Slider的滑块与滑轨显示样式。类型:SliderStyle默认值:SliderStyle.OutSet
  • direction(API Version 8+):设置滑动条滑动方向为水平或竖直方向。类型:Axis默认值:Axis.Horizontal
  • reverse(API Version 8+):设置滑动条取值范围是否反向。类型:boolean默认值:false说明:横向Slider默认为从左往右滑动,竖向Slider默认为从上往下滑动。

3.2 主要属性和事件说明

  • blockColor:设置滑块的颜色。类型:ResourceColor说明:当滑块形状设置为SliderBlockType.DEFAULT时,blockColor可设置默认圆形滑块颜色。
  • trackColor:设置滑轨的背景颜色。类型:ResourceColor | LinearGradient说明:从API version 12开始支持利用LinearGradient设置滑轨的渐变色。
  • selectedColor:设置滑轨的已滑动部分颜色。类型:ResourceColor默认值:$r(‘sys.color.ohos_id_color_emphasize’)
  • showSteps:设置当前是否显示步长刻度值。类型:boolean默认值:false
  • showTips:设置滑动时是否显示气泡提示。类型:boolean参数:content?: ResourceStr默认值:false说明:当direction的值为Axis.Horizontal时,tip显示在滑块上方,如果上方空间不够,则在下方显示。值为Axis.Vertical时,tip显示在滑块左边,如果左边空间不够,则在右边显示。
    -** trackThickness**(API Version 8+):设置滑轨的粗细。类型:Length默认值:当参数style的值设置为SliderStyle.OutSet时为4.0vp,SliderStyle.InSet时为20.0vp。
  • onChange:Slider拖动或点击时触发事件回调。
    类型:(value: number, mode: SliderChangeMode) => void
    说明:Begin和End状态当手势点击时都会触发,Moving和Click状态当value值发生变化时触发。当连贯动作为拖动动作时,不触发Click状态。

4. 组件设计

在实现自定义的时间滑动条组件之前,我们需要设计组件的基本结构和功能模块。以下是组件设计的详细说明。

4.1 组件结构

  • RelativeContainer:作为整个组件的容器,确保组件可以相对于父容器进行布局。
  • Column:用于垂直排列小时选择器、分钟选择器和确认按钮。
  • Row:用于水平排列文本标签和滑动条。
  • Text:用于显示标题、标签和当前选择的时间数值。
  • Slider:用于允许用户滑动选择小时和分钟。
  • AddButtonComponent:自定义的按钮组件,用于提交选择的时间。

4.2 组件属性和方法

  • @State timeId: string:用于唯一标识时间设置事件。
  • confirm: ((dwellTime: DwellTime) => void) | undefined:回调函数,用于处理用户点击确认按钮后的逻辑。
  • @Link isShow: boolean:用于控制按钮的显示状态。
  • @State hour: number:用于存储当前选择的小时。
  • @State minute: number:用于存储当前选择的分钟。
  • @State widthProportion: BreakpointState<string>:用于存储不同屏幕尺寸下的宽度比例。
  • @State buttonProportion: BreakpointState<string>:用于存储不同屏幕尺寸下的按钮宽度比例。

4.3 生命周期方法

  • aboutToAppear:组件即将显示时调用,用于初始化和绑定事件。
    通过BreakpointSystem.getInstance().attach方法绑定宽度比例和按钮比例。
    启动BreakpointSystem以监测屏幕尺寸变化。
    使用emitter.once监听用户点击确认按钮的事件。
  • aboutToDisappear:组件即将消失时调用,用于解绑事件。
    通过BreakpointSystem.getInstance().detach方法解绑宽度比例和按钮比例。

5. 组件实现

在明确了项目需求和组件设计之后,我们需要逐步实现自定义的时间滑动条组件。以下是具体的实现步骤和代码示例。

5.1 小时和分钟选择器

小时选择器

Row() {
  Text("小时")
    .fontSize(18)
    .fontColor($r('app.color.main_add_background'))
    .margin({ left: 15, right: 15 });

  Text(this.hour.toFixed(0).toString())
    .fontSize(16)
    .height(26)
    .width(60)
    .fontColor('#000000')
    .textAlign(TextAlign.Center)
    .backgroundColor($r('app.color.background_color_lv6'))
    .borderRadius(4);

  Slider({
    value: this.hour,
    min: 0,
    max: 23,
    step: 1,
    style: SliderStyle.OutSet,
  })
    .blockColor($r('app.color.cancel_background'))
    .blockStyle({ type: SliderBlockType.DEFAULT })
    .blockBorderWidth(6)
    .trackColor($r('app.color.cancel_background'))
    .trackThickness(5)
    .selectedColor('#89BA20')
    .onChange((value: number, mode: SliderChangeMode) => {
      this.hour = value;
    })
    .width("60%");
}
.margin({ top: this.widthProportion.value == '50%' ? 4 : 12, bottom: 12 });
  • 使用Row组件水平排列“小时”标签和滑动条。
  • 使用Text组件显示当前选择的小时值。
  • 使用Slider组件允许用户滑动选择小时,范围为0到23。

分钟选择器

Row() {
  Text("分钟")
    .fontSize(15)
    .fontColor($r('app.color.main_add_background'))
    .margin({ left: 15, right: 15 });

  Text(this.minute.toFixed(0).toString())
    .fontSize(16)
    .height(26)
    .width(60)
    .fontColor('#000000')
    .textAlign(TextAlign.Center)
    .backgroundColor($r('app.color.background_color_lv6'))
    .borderRadius(4);

  Slider({
    value: this.minute,
    min: 0,
    max: 59,
    step: 1,
    style: SliderStyle.OutSet,
  })
    .blockColor($r('app.color.cancel_background'))
    .blockStyle({ type: SliderBlockType.DEFAULT })
    .blockBorderWidth(6)
    .trackColor($r('app.color.cancel_background'))
    .trackThickness(5)
    .selectedColor('#89BA20')
    .onChange((value: number, mode: SliderChangeMode) => {
      this.minute = value;
    })
    .width("60%");
}
.margin({ top: 12, bottom: this.widthProportion.value == '50%' ? 5 : 42 });

和小时选择器类似

  • 使用Row组件水平排列“分钟”标签和滑动条。
  • 使用Text组件显示当前选择的分钟值。
  • 使用Slider组件允许用户滑动选择分钟,范围为0到59。

5.2 确认按钮导入

使用自定义的AddButtonComponent组件,设置其宽度和对齐方式。

AddButtonComponent({ isTrue: this.isShow, buttonId: this.timeId })
  .width(this.buttonProportion.value)
  .align(Alignment.Center);

接下来我们简单看一下这个自定义的按钮组件。用的按钮的渐变可以参考组内另一成员的博客按钮颜色渐变和阴影

import emitter from '@ohos.events.emitter';

@Component
export struct AddButtonComponent {

   @Link isTrue: boolean;
   buttonId: string = "";

  build() {
    //4 添加按钮
    Row() {
      Button("取消", { type: ButtonType.Normal })
        .onClick(() => {
          //取消逻辑
          this.isTrue = !this.isTrue;
          console.log(`${this.isTrue}`)
        })
        .height(40)
        .width("43%")
        .backgroundColor($r("app.color.cancel_background"))
        .fontColor($r("app.color.font_color"))
        .fontSize(18)
        .borderRadius(5)
        .onClick(() => {
          this.isTrue = false;
          let eventData: emitter.EventData = {
            data: {"id": this.buttonId}
          };
          // 发送事件
          emitter.emit("取消", eventData);
        })

      Button("确定", { type: ButtonType.Normal })
        .height(40)
        .width("43%")
        .fontColor($r("app.color.confirm_font"))
        .linearGradient({
          direction: GradientDirection.Left,
          colors: [[$r("app.color.confirm_background1"), 0.0], [$r("app.color.confirm_background2"), 1.0]]
        })
        .fontSize(18)
        .borderRadius(5)
        .onClick(() => {
          let eventData: emitter.EventData = {
            data: {"id": this.buttonId}
          };
          // 发送事件
          emitter.emit(this.buttonId, eventData);
          // 弹窗关闭
          this.isTrue = !this.isTrue;
          this.isTrue = false;
        })

    }
    .justifyContent(FlexAlign.SpaceAround)
    .padding({left: 12, right: 12})
    .width("100%")
  }
}

他的功能就是取消按钮,当用户点击“取消”按钮时,设置isTrue为false以关闭弹窗。使用emitter.emit发送“取消”事件,传递相关数据。确定按钮,当用户点击“确定”按钮时,使用emitter.emit发送buttonId事件,传递相关数据。设置isTrue为false以关闭弹窗。

完整代码

import { AddButtonComponent } from "../views/ButtonView";
import { emitter } from "@kit.BasicServicesKit";
import { DwellTime } from "../models/LocationModel";
import { BreakpointState, BreakpointSystem } from "../common/breakpointsystem";

@Component
export struct TimeComponent {

  @State timeId: string = "设置驻留时间";
  confirm: ((dwellTime: DwellTime) => void) | undefined = undefined;
  @Link isShow: boolean;
  @State hour: number = 0;
  @State minute: number = 0;
  @State widthProportion: BreakpointState<string> = BreakpointState.of({ sm: "100%", lg: "50%" , md: "50%" });
  @State buttonProportion: BreakpointState<string> = BreakpointState.of({ sm: "100%", lg: "65%", md: "65%" });

  aboutToAppear(): void {
    BreakpointSystem.getInstance().attach(this.widthProportion)
    BreakpointSystem.getInstance().attach(this.buttonProportion)
    BreakpointSystem.getInstance().start()
    emitter.once(this.timeId, () => {
      console.log("===用户点击了确定" + this.timeId)
        if(this.confirm){
          this.confirm({hour: this.hour, minute: this.minute});
        }
    })
  }
  aboutToDisappear() {
    BreakpointSystem.getInstance().detach(this.widthProportion)
    BreakpointSystem.getInstance().detach(this.buttonProportion)
  }
  build() {
    RelativeContainer() {
      Column() {
        Text("添加驻留时间")
          .fontSize(22)
          .padding(20)
          .width('100%')
          .margin({top: 5, bottom: this.widthProportion.value == '50%' ? 0 : 5})
    	//见小时选择器
		//见分钟选择器
		//见上面添加按钮
      }
      .width("100%")
      .height("100%")
      .backgroundColor($r('app.color.background_color'))
      .borderRadius({
        topLeft: 24,
        topRight: 24,
        bottomLeft: this.widthProportion.value == '50%' ? 24 : 0,
        bottomRight: this.widthProportion.value == '50%' ? 24 : 0
      })
    }
  }
}

6. 总结

在完成了基于Slider实现自定义时间滑动条组件的开发后,我们成功实现了允许用户通过滑动条设置小时和分钟的功能。通过使用emitter库进行事件监听和处理,并利用BreakpointState和BreakpointSystem实现响应式设计,组件能够在不同屏幕尺寸下提供良好的用户体验。未来,我们可以进一步优化滑动条的样式和动画效果,增强功能,如时间范围选择和格式化显示,并通过用户反馈提升整体用户体验。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2024-12-30 17:17:07修改
收藏
回复
举报
回复
    相关推荐