107 Star 880 Fork 419

OpenHarmony/codelabs

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
.gitee
Ability
Card
CommonEventAndNotification/AlarmClock
Data
Distributed
ETSUI
AnimateRefresh
Animation
ArkTSComponents
CanvasComponent
CustomDialog
ElectronicAlbum
FlexLayout
List
List_HDC
MultipleDialog
AppScope
entry
figures
hvigor
public_sys-resources
LICENSE
README.md
build-profile.json5
hvigorfile.ts
oh-package.json5
OHLayoutAlign
PixelConversion
RankingDemo
SecondLevelLinkage
ShoppingEts
SimpleCalculator
SliderExample
SwiperArkTS
TargetManagement
ToDoListArkTS
TransitionAnimation
WebComponent
WebCookie
EfficiencyEnhancementKit/SuperVisualSample
ExcellentCase
GraphicImage/GestureScreenshot
JSUI
Media
NativeAPI
NetworkManagement/NewsDataArkTS
Security
ThirdPartyComponents/ThirdPartyLibrary
README.md
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

构建多种样式弹窗(ArkTS)

介绍

本篇Codelab将介绍如何使用弹窗功能,实现四种类型弹窗。分别是:警告弹窗、自定义弹窗、日期滑动选择器弹窗、文本滑动选择器弹窗。需要完成以下功能:

  1. 点击左上角返回按钮展示警告弹窗。
  2. 点击出生日期展示日期滑动选择器弹窗。
  3. 点击性别展示文本滑动选择器弹窗。
  4. 点击兴趣爱好(多选)展示自定义弹窗。

相关概念

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

  2. 搭建烧录环境。

    1. 完成DevEco Device Tool的安装
    2. 完成RK3568开发板的烧录
  3. 搭建开发环境。

    1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用真机进行调测

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。

├──entry/src/main/ets             // 代码区 
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets   // 常量类
│  │  └──utils
│  │     ├──CommonUtils.ets       // 弹窗操作工具类
│  │     └──Logger.ets            // 日志打印工具类
│  ├──entryability
│  │  └──EntryAbility.ets         // 程序入口类
│  ├──pages
│  │  └──HomePage.ets             // 主页面
│  ├──view
│  │  ├──CustomDialogWidget.ets   // 自定义弹窗组件
│  │  ├──TextCommonWidget.ets     // 自定义Text组件
│  │  └──TextInputWidget.ets      // 自定义TextInput组件
│  └──viewmodel
│     └──HobbyModel.ets           // 兴趣爱好model类
└──entry/src/main/resources       // 资源文件目录

构建主页面

应用主页面采用Column容器嵌套自定义组件形式完成页面整体布局,效果如图所示:

从上面效果图可以看出,主界面由2个相同样式的文本输入框和3个相同样式的文本布局组成。我们可以将文本输入框抽取成TextInputWidget子组件。再将文本布局抽取成TextCommonWidget子组件。

  1. 在ets目录下,点击鼠标右键 > New > Directory,新建名为view的自定义子组件目录。然后在view目录下,点击鼠标右键 > New > ArkTS File,新建两个ArkTS文件,分别为TextInputWidget子组件、TextCommonWidget子组件。

  2. 文本输入框抽取成TextInputWidget子组件,效果如图所示:

    // TextInputWidget.ets
    @Component
    export default struct TextInputWidget {
      // 文本框左侧图片
      private inputImage?: Resource; 
      // 文本框提示
      private hintText?: Resource;
    
      build() {
        Row() {
          Image(this.inputImage)
            ...
          TextInput({ placeholder: this.hintText })
            ...
        }
        ...
      }
    }
    
  3. 文本布局抽取成TextCommonWidget子组件,效果如图所示:

    // TextCommonWidget.ets
    @Component
    export default struct TextCommonWidget {
      // 显示内容
      @Link content: string;
      // 文字标题左侧图片
      private textImage?: Resource;
      // 文本标题
      private title?: Resource;
      // 点击事件回调
      onItemClick: () => void = () => {};
    
      build() {
        Row() {
          Image(this.textImage)
            ...
          Text(this.title)
            ...
          Text(this.content)
            ...
          Image($r('app.media.ic_arrow'))
            ....
        }
        .onClick(this.onItemClick)
        ...
      } 
    }
    
  4. 在HomePage主界面引用TextInputWidget和TextCommonWidget子组件,然后初始化出生日期、性别、兴趣爱好默认数据。

    // HomePage.ets
    @Entry
    @Component
    struct HomePage {
      @State birthdate: string = '';
      @State sex: string = '';
      @State hobbies: string = '';
    
      build() {
        Column() {
          ...
          TextInputWeight({
            inputImage: $r("app.media.ic_nickname"),
            hintText: $r("app.string.text_input_hint")
          })
          TextCommonWeight({
            textImage: $r("app.media.ic_birthdate"),
            title: $r("app.string.title_birthdate"),
            content: $birthdate,
            onItemClick: () => {
              CommonUtils.datePickerDialog((birthValue: string) => {
                this.birthdate = birthValue;
              });
            }
          }) 
          TextCommonWeight({
            textImage: $r("app.media.ic_sex"),
            title: $r("app.string.title_sex"),
            content: $sex,
            onItemClick: () => {
              CommonUtils.textPickerDialog(this.sexArray, (sexValue: string) => {
                this.sex = sexValue;
              });
            }
          })
          TextInputWeight({
            inputImage: $r("app.media.ic_signature"),
            hintText: $r("app.string.text_input_signature")
          })
          TextCommonWeight({
            textImage: $r("app.media.ic_hobbies"),
            title: $r("app.string.title_hobbies"),
            content: $hobbies,
            onItemClick: () => {
              this.customDialogController.open();
            }
          })
        }
        ...
      }
    }
    

警告弹窗

点击主页面左上角返回按钮,通过CommonUtils.alertDialog方法弹出警告弹窗,提醒用户是否进行当前操作,效果如图所示:

// CommonUtils.ets
alertDialog(context: Context.UIAbilityContext) {
  AlertDialog.show({
    // 提示信息
    message: $r('app.string.alert_dialog_message'), 
    // 弹窗显示位置
    alignment: DialogAlignment.Bottom,
    // 弹窗偏移位置
    offset: {
      dx: 0,
      dy: CommonConstants.DY_OFFSET
    },
    primaryButton: {
      ...
    },
    secondaryButton: {
      // 退出应用
      context.terminateSelf();
      ...
    }
  });
}

日期滑动选择器弹窗

点击出生日期选项,通过CommonUtils.datePickerDialog方法弹出日期选择器弹窗,根据需要选择相应时间,效果如图所示:

// CommonUtils.ets
datePickerDialog(dateCallback) {
  DatePickerDialog.show({
    // 开始时间
    start: new Date(CommonConstants.START_TIME),
    // 结束时间
    end: new Date(CommonConstants.END_TIME), 
    // 当前选中时间
    selected: new Date(),
    // 是否显示农历
    lunar: false,
    onAccept: (value: DatePickerResult) => {
      let year = value.year as number;
      let month = value.month as number + CommonConstants.PLUS_ONE;
      let day = value.day as number;
      let birthdate: string = this.getBirthDateValue(year, month, day);
      dateCallback(birthdate);
    }
  });
}

// 获取出生日期值
getBirthDateValue(year: number, month: number, day: number): string {
  let birthdate: string = `${year}${CommonConstants.DATE_YEAR}${month}` +
    `${CommonConstants.DATE_MONTH}${day}${CommonConstants.DATE_DAY}`;
  return birthdate;
}  

// HomePage.ets
build() {
  Column() {
    ...
    TextCommonWeight({
      textImage: $r('app.media.ic_birthdate'),
      title: $r("app.string.title_birthdate"),
      content: $birthdate,
      onItemClick: () => {
        CommonUtils.datePickerDialog((birthValue: string) => {
          this.birthdate = birthValue;
        });
      }
    })
    ...
  }
  ...
}

文本滑动选择器弹窗

点击性别选项,通过CommonUtils.textPickerDialog方法弹出性别选择器弹窗,根据需要选择相应性别,效果如图所示:

// CommonUtils.ets
textPickerDialog(sexArray: Resource, sexCallback: (sexValue: string) => void) {
  TextPickerDialog.show({
    range: sexArray,
    selected: 0,
    onAccept: (result: TextPickerResult) => {
      sexCallback(result.value);
    },
    onCancel: () => {
      ...
    }
  });
}

// HomePage.ets
build() {
  Column() {
    ...
    TextCommonWeight({
      textImage: $r('app.media.ic_sex'),
      title: $r("app.string.title_sex"),
      content: $sex,
      onItemClick: () => {
        CommonUtils.textPickerDialog(this.sexArray, (sexValue: string) => {
          this.sex= sexValue;
        });
      }
    })
    ...
  }
  ...
}

自定义弹窗

点击兴趣爱好选项,通过customDialogController.open方法弹出自定义弹窗,根据需要选择相应的兴趣爱好,效果如图所示:

自定义弹窗实现分为以下步骤:

  1. 在view目录下,点击鼠标右键 > New > ArkTS File,新建一个ArkTS文件,然后命名为CustomDialogWeight子组件。

  2. 在CustomDialogWeight的aboutToAppear方法,通过manager.getStringArrayValue方法获取本地资源数据进行初始化。

    // CustomDialogWeight.ets
    @State hobbyModels: HobbyModel[] = [];
    
    aboutToAppear() {
      let context: Context = getContext(this);
      if (CommonUtils.isEmpty(context) || CommonUtils.isEmpty(context.resourceManager)) {
        Logger.error(CommonConstants.TAG_CUSTOM, 'context or resourceManager is null');
        return;
      }
      let manager = context.resourceManager;
      manager.getStringArrayValue($r("app.strarray.hobbies_data").id, (error, hobbyArray) => {
        if (!CommonUtils.isEmpty(error)) {
          Logger.error(CommonConstants.TAG_CUSTOM, 'error = ' + JSON.stringify(error));
        } else {
          hobbyArray.forEach((hobbyItem: string) => {
            let hobbyModel = new HobbyModel();
            hobbyModel.label = hobbyItem;
            hobbyModel.isChecked = false;
            this.hobbyModels.push(hobbyModel);
          });
        }
      });
    }
    
  3. 当用户点击确定按钮时,通过setHobbiesValue方法处理自定义弹窗选项结果。

    // CustomDialogWeight.ets
    @State hobbyModels: HobbyModel[] = [];
    @Link hobbies: string;
    
    // 处理自定义弹窗选项结果
    setHobbiesValue(hobbyModels: HobbyModel[]) {
      if (CommonUtils.isEmptyArr(hobbyModels)) {
        Logger.error(CommonConstants.TAG_CUSTOM, 'hobbyModels length is 0');
        return;
      }
      let hobbiesText: string = '';
      hobbiesText = hobbyModels.filter((isCheckItem: HobbyModel) => isCheckItem?.isChecked)
        .map((checkedItem: HobbyModel) => {
          return checkedItem.label;
        })
        .join(CommonConstants.COMMA);
      if (hobbiesText.length > 0) {
        this.hobbies = hobbiesText;
      }
    }
    
    build() {
      Column() {
        ...
        Row() {
          Button($r('app.string.cancel_button'))
            .dialogButtonStyle()
            .onClick(() => {
              this.controller.close();
            })
          Blank()
            ...
          Button($r('app.string.definite_button'))
            .dialogButtonStyle()
            .onClick(() => {
              this.setHobbiesValue(this.hobbyModels);
              this.controller.close();
            })
        }
      }
      ...
    }
    
    @Extend(Button) function dialogButtonStyle() {
      ....
    }
    
  4. 通过@Link修饰的hobbies把值赋给HomePage的hobbies,然后hobbies刷新显示内容。

    // HomePage.ets
    @State hobbies: string = '';
    customDialogController: CustomDialogController = new CustomDialogController({
      builder: CustomDialogComponent({
        hobbies: $hobbies
      }),
      alignment: DialogAlignment.Bottom,
      customStyle: true,
      offset: {
        dx: 0,
        dy: CommonConstants.DY_OFFSET
      }
    });
    
    build() {
      Column() {
        ...
        TextCommonWeight({
          textImage: $r('app.media.ic_hobbies'),
          title: $r("app.string.title_hobbies"),
          content: $hobbies,
          onItemClick: () => {
            // 打开自定义弹窗
            this.customDialogController.open();
          }
        })
      }
      ...
    }
    

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 使用CustomDialogController实现自定义弹窗。
  2. 使用AlertDialog实现警告弹窗。
  3. 使用DatePickerDialog实现日期滑动选择弹窗。
  4. 使用TextPickerDialog实现文本滑动选择弹窗。

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/openharmony/codelabs.git
git@gitee.com:openharmony/codelabs.git
openharmony
codelabs
codelabs
master

搜索帮助