DIY可视化封装的鸿蒙ArkUI单选组件

250 阅读2分钟

鸿蒙Radio是单选框组件,通常用于提供相应的用户交互选择项,同一组的Radio中只有一个可以被选中。 ArkUI创建一个单选框,其中value是单选框的名称,group是单选框的所属群组名称。checked属性可以设置单选框的状态,状态分别为false和true时,设置为true时表示单选框被选中。Radio仅支持选中和未选中两种样式,不支持自定义颜色和形状。

Radio({ value: 'Radio1', group: 'radioGroup' }) .checked(false)

Radio({ value: 'Radio2', group: 'radioGroup' }) .checked(true)

当使用的时,发现不是很友好,没有对应的文本,而且点击事件不方便选中单选框。

image.png

image.png

`

import {DynamicObject} from './type'
/**
 * 自定义颜色
 */
@Component
export default  struct DiygwRadio{
  //绑定的值
  @Link @Watch('onValue') value:string;
  // 保存所有单选框的名称
  @State list: DynamicObject[] = [];
  // 隐藏值
  @State valueField: string = 'value';
  // 显示值
  @State labelField: string = 'label';
  // 选中/未选中状态下的图标
  @State checkedValues: Resource[] = [];
  //选中图标
  @State checkedImg: Resource = $r('app.media.radioon');
  //未选中图标
  @State noCheckedImg: Resource = $r('app.media.radio');


  //未选中图标
  @State labelImg: Resource = $r('app.media.user');
  //是否文本图片
  @State isLabelImg: boolean = false;
  @State labelImgWidth: number = 20;
  @State labelImgHeight: number = 20;
  //标题文本
  @State label:string = '单选';
  //水平状态时,文本占大小
  @State labelWidth:number = 80;
  //是否标题文本换行
  @State isWrapLabel:boolean = false;
  //是否标题文本
  @State isLabel:boolean = true;
  //文本字体大小
  @State textSize:number = 14;
  //选中图版本大小
  @State imgSize:number = 28;
  //每个占比
  @State itemWidth:string = '33%';
  //每行个数
  @State col:number = 3;
  //组件内边距
  @State formPadding:number = 5;

  //初始化选中
  initCheck(){
    for (let i = 0; i < this.list.length; i++) {
      if(this.list[i][this.valueField] == this.value) {
        this.checkedValues[i] = this.checkedImg;
      }else{
        this.checkedValues[i] = this.noCheckedImg;
      }
    }
  }

  //监听选中
  onValue() {
     this.initCheck()
  }

  onChecked(index: number){
    //点击文本选中当前单选框
    for (let i = 0; i < this.list.length; i++) {
      this.checkedValues[i] = this.noCheckedImg;
    }
    this.checkedValues[index] = this.checkedImg;
    this.value = this.list[index][this.valueField];
  }

  build() {
    Flex({
      alignItems:this.isWrapLabel?ItemAlign.Start:ItemAlign.Center,
      direction:this.isWrapLabel?FlexDirection.Column:FlexDirection.Row,
      justifyContent:FlexAlign.Start
    }){
      if(this.isLabel){
        Row(){
          if(this.isLabelImg){
            Image(this.labelImg)
              .width(this.labelImgWidth)
              .height(this.labelImgHeight)
              .margin({ left:3 })
          }
          Text(this.label).width(this.isWrapLabel?'100%':this.labelWidth).fontSize(this.textSize).margin({
            bottom:this.isWrapLabel?10:0
          }).textAlign(TextAlign.Start);
        }
      }
      Flex({
        wrap:FlexWrap.Wrap
      }){
        ForEach(this.list, (item: any,index: number) => {
            Row(){
              Image(this.checkedValues[index])
                .borderRadius('50%')
                .size({width: this.imgSize , height: this.imgSize}).margin({
                top:1,
                bottom:1
              })
              Text(item[this.labelField])
                .fontSize(this.textSize)
                .margin({left: 10})
            }.onClick(()=>{
              this.onChecked(index)
            }).width(this.itemWidth)
        })
      }.width('100%')
    }.height(Math.ceil(this.list.length/this.col)*38+(this.isWrapLabel?18:0)).padding(this.formPadding)
    .onAppear(() => {
      let widths=['100%','50%','33%','25%']
      let col = widths.indexOf(this.itemWidth) + 1
      this.col = col
      this.initCheck()
    })
  }
}

`