构建多种样式的弹窗(案例)

介绍

img

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

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

相关概念

  • 警告弹窗:显示警告弹窗组件,可设置文本内容与响应回调。
  • 自定义弹窗: 通过CustomDialogController类显示自定义弹窗。
  • 日期滑动选择器弹窗:根据指定范围的Date创建可以选择日期的滑动选择器,展示在弹窗上。
  • 文本滑动选择器弹窗:根据指定的选择范围创建文本选择器,展示在弹窗上。

完整示例

gitee源码地址

源码下载

构建多种样式弹窗(ArkTS).zip

代码结构解读

本篇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
│     └──HobbyItem.ets            // 兴趣爱好类
└──entry/src/main/resources       // 资源文件目录

构建主页面

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

img

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

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

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

img

// TextInputWidget.ets
@Component
export default struct TextInputWidget {
  // 文本框左侧图片
  private inputImage?: Resource; 
  // 文本框提示
  private hintText?: Resource;

  build() {
    Row() {
      Image(this.inputImage !== undefined ? this.inputImage : '')
        ...
      TextInput({ placeholder: this.hintText })
        ...
    }
    ...
  }
}

文本布局抽取成TextCommonWidget子组件,效果如图所示:

img

// TextCommonWidget.ets
@Component
export default struct TextCommonWidget {
  // 显示内容
  @Link content: string;
  // 文字标题左侧图片
  private textImage?: Resource;
  // 文本标题
  private title?: Resource;
  // 点击事件回调
  onItemClick = () => {};

  build() {
    Row() {
      Image(this.textImage !== undefined ? this.textImage : '')
        ...
      Text(this.title)
        ...
      Text(this.content)
        ...
      Image($r('app.media.ic_arrow'))
        ...
    }
    .onClick(this.onItemClick)
    ...
  } 
}

在HomePage主界面引用TextInputWidget和TextCommonWidget子组件,然后初始化出生日期、性别、兴趣爱好默认数据。

// HomePage.ets
@Entry
@Component
struct HomePage {
  @State birthdate: string = '';
  @State sex: string = '';
  @State hobbies: string = '';
  ...

  build() {
    Column() {
      ...
      TextInputWidget({
        inputImage: $r('app.media.ic_nickname'),
        hintText: $r('app.string.text_input_hint')
      })
      TextCommonWidget({
        textImage: $r('app.media.ic_birthdate'),
        title: $r('app.string.title_birthdate'),
        content: $birthdate,
        onItemClick: () => {
          CommonUtils.datePickerDialog((birthValue: string) => {
            this.birthdate = birthValue;
          });
        }
      })
      TextCommonWidget({
        textImage: $r('app.media.ic_sex'),
        title: $r('app.string.title_sex'),
        content: $sex,
        onItemClick: () => {
          CommonUtils.textPickerDialog(this.sexArray, (sexValue: string) => {
            this.sex = sexValue;
          });
        }
      })
      TextInputWidget({
        inputImage: $r('app.media.ic_signature'),
        hintText: $r('app.string.text_input_signature')
      })
      TextCommonWidget({
        textImage: $r('app.media.ic_hobbies'),
        title: $r('app.string.title_hobbies'),
        content: $hobbies,
        onItemClick: () => {
          this.customDialogController.open();
        }
      })
    }
    ...
  }
}

警告弹窗

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

img

// 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: {
      value: $r('app.string.cancel_button'),
      action: () => {
        ...
      }
    },
    secondaryButton: {
      value: $r('app.string.definite_button'),
      action: () => {
        // 退出应用
        context.terminateSelf();
        ...
      }
    }
  });
}

日期滑动选择器弹窗

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

img

// CommonUtils.ets
datePickerDialog(dateCallback: Function) {
  DatePickerDialog.show({
    // 开始时间
    start: new Date(CommonConstants.START_TIME),
    // 结束时间
    end: new Date(), 
    // 当前选中时间
    selected: new Date(CommonConstants.SELECT_TIME),
    // 是否显示农历
    lunar: false,
    onAccept: (value: DatePickerResult) => {
      let year: number = Number(value.year);
      let month: number = Number(value.month) + CommonConstants.PLUS_ONE;
      let day: number = Number(value.day);
      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() {
    ...
    TextCommonWidget({
      textImage: $r('app.media.ic_birthdate'),
      title: $r('app.string.title_birthdate'),
      content: $birthdate,
      onItemClick: () => {
        CommonUtils.datePickerDialog((birthValue: string) => {
          this.birthdate = birthValue;
        });
      }
    })
    ...
  }
  ...
}

文本滑动选择器弹窗

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

img

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

// HomePage.ets
build() {
  Column() {
    ...
    TextCommonWidget({
      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方法弹出自定义弹窗,根据需要选择相应的兴趣爱好,效果如图所示:

img

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

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

// CustomDialogWidget.ets
@State hobbyItems: HobbyItem[] = [];
...
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((hobby: string) => {
        let hobbyItem = new HobbyItem();
        hobbyItem.label = hobby;
        hobbyItem.isChecked = false;
        this.hobbyItems.push(hobbyItem);
      });
    }
  });
}

当用户点击确定按钮时,通过setHobbiesValue方法处理自定义弹窗选项结果。

// CustomDialogWidget.ets
@State hobbyItems: HobbyItem[] = [];
@Link hobbies: string;
private controller?: CustomDialogController;

// 处理自定义弹窗选项结果
setHobbiesValue(hobbyItems: HobbyItem[]) {
  if (CommonUtils.isEmptyArr(hobbyItems)) {
    Logger.error(CommonConstants.TAG_HOME, 'hobbyItems length is 0');
    return;
  }
  let hobbiesText: string = '';
  hobbiesText = hobbyItems.filter((isCheckItem: HobbyItem) => isCheckItem?.isChecked)
    .map<string>((checkedItem: HobbyItem) => {
      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.hobbyItems);
          this.controller?.close();
        })
    }
  }
  ...
}

@Extend(Button) function dialogButtonStyle() {
  ....
}

通过@Link修饰的hobbies把值赋给HomePage的hobbies,然后hobbies刷新显示内容。

// HomePage.ets
@State hobbies: string = '';
customDialogController: CustomDialogController = new CustomDialogController({
  builder: CustomDialogWidget({
    hobbies: $hobbies
  }),
  alignment: DialogAlignment.Bottom,
  customStyle: true,
  offset: {
    dx: 0,
    dy: CommonConstants.DY_OFFSET
  }
});

build() {
  Column() {
    ...
    TextCommonWidget({
      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实现文本滑动选择弹窗。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/303095.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

树莓派4B使用ncnn部署yolov5-Lite,推理耗时 247ms 包含前后处理

一. 引言 最近在玩树莓派&#xff0c;想在树莓派上不是一个目标检测算法&#xff0c;大致看了一下&#xff0c;目前开源的大家都在使用yolov5-Lite&#xff0c;使用ncnn去推理加速&#xff0c;于是自己也尝试部署&#xff0c;在此记录一下&#xff0c;个人踩的坑。 二. 版本选…

后端 API 接口文档 Swagger 使用

Swagger 是什么 swagger是一款可以根据 restful 风格生成的接口开发文档&#xff0c;并且支持做测试的一款中间软件。 例如当我们在开发前后端分离项目时&#xff0c;当后端开发完一个功能想要测试时&#xff0c;若此时还没有相应的前端页面发起请求&#xff0c;可以通过 swag…

java回溯算法、最短路径算法、最小生成树算法

回溯算法 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。 最短路径算法 从某顶点出发&#xff0c;沿图的边到达另一顶点所经过的路径中…

【QML COOK】- 002-添加一个图片

1. 编辑main.qml import QtQuickWindow {width: 800height: 800visible: truetitle: qsTr("Hello World")Image {anchors.fill: parentsource: "qrc:/Resources/Images/arrow.png"} }将Window的width和height都改成800&#xff0c;因为我们要添加的图片大…

Spring AOP概念

什么是 AOP &#xff1f; AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是 Spring …

Mac 环境多JDK安装与切换

一、下载jdk 去Oracle官网上下载想要安装的jdk版本&#xff0c;M芯片选择arm架构的.bmg格式的文件。 https://www.oracle.com/java/technologies/downloads/。 二、安装jdk 2.1 双击下载的文件&#xff0c;安装步骤一步步点继续就好。 2.2 安装完成后会在/Library/Java/JavaV…

常见测试技术都有哪些?

测试技术是用于评估系统或组件的方法&#xff0c;目的是发现它是否满足给定的要求。系统测试有助于识别缺口、错误&#xff0c;或与实际需求不同的任何类型的缺失需求。测试技术是测试团队根据给定的需求评估已开发软件所使用的最佳实践。这些技术可以确保产品或软件的整体质量…

2024年甘肃省职业院校技能大赛 高职学生组电子与信息大类信息安全管理与评估赛项样题卷①

2024年甘肃省职业院校技能大赛 高职学生组电子与信息大类信息安全管理与评估赛项样题 第一阶段&#xff1a;第二阶段&#xff1a;模块二 网络安全事件响应、数字取证调查、应用程序安全第二阶段 网络安全事件响应第一部分 网络安全事件响应第二部分 数字取证调查第三部分 应用程…

网络通信(12)-C#TCP客户端封装帮助类实例

本文使用Socket在C#语言环境下完成TCP客户端封装帮助类的实例。 实例完成的功能: 客户端与服务器连接,实现实时刷新状态。 客户端接收服务器的数据。 客户端发送给服务器的数据。 客户端实时判定状态,断开连接后自动重连。 客户端与服务器端发送心跳包。 在VS中创建C…

电商引流模式:广告电商

广告电商模式是一种将广告收入与电商业务相结合的商业模式。在这种模式下&#xff0c;电商企业通过向消费者提供免费或低价的商品或服务&#xff0c;吸引大量用户关注和参与。同时&#xff0c;电商企业通过与广告主合作&#xff0c;将广告投放到自己的平台上&#xff0c;通过广…

接口工具Apifox

最近发现一款接口测试工具--apifox&#xff0c;我我们很难将它描述为一款接口管理工具 或 接口自测试工具。 官方给了一个简单的公式&#xff0c;更能说明apifox可以做什么。 Apifox Postman Swagger Mock JMeter Apifox的特点&#xff1a; 接口文档定义&#xff1a; Apif…

1.8.。。

1 有道云笔记 2 #include "mywidget.h"myWidget::myWidget(QWidget *parent): QWidget(parent) {//设置窗口大小&#xff0c;背景颜色&#xff0c;纯净窗口this->setFixedSize(700,500);this->setStyleSheet("background-color:white");this->…

Dockerfile基本结构及编写详解

文章目录 1 Dockerfile1.1 Dockerfile的基本结构1.2 Dockerfile文件说明1.3 Dockerfile常见命令1.4 build命令1.5 部署微服务1.6 docker-compose部署 1 Dockerfile ​ Dockerfile其实就是我们用来构建Docker镜像的源码&#xff0c;当然这不是所谓的编程源码&#xff0c;而是一…

深入了解Pytest中的Mocking:简化测试,避免依赖问题!

在软件开发中&#xff0c;测试是确保代码质量的关键步骤之一。而在测试中&#xff0c;经常需要模拟&#xff08;Mock&#xff09;一些对象或函数&#xff0c;以确保测试的独立性和可靠性。在Pytest中&#xff0c;Mocking是一个强大的工具&#xff0c;能够简化测试过程&#xff…

【Docker】部署mysql 和 tomcat

目录 部署MySQL 1.搜索镜像 2. 拉取镜像 部署Tomcat 1. 搜索镜像 2.拉取镜像 3.查看镜像 部署MySQL 1.搜索镜像 docker search mysql 2. 拉取镜像 通过mysql 镜像创建对应的容器&#xff0c;并设置端口映射&#xff0c;目录映射 创建mysql 的目录 docker run -id \ …

【PostgreSQL】在DBeaver中实现序列、函数、视图、触发器设计

【PostgreSQL】在DBeaver中实现序列、函数、触发器、视图设计 基本配置一、序列1.1、序列使用1.1.1、设置字段为主键&#xff0c;数据类型默认整型1.1.2、自定义序列&#xff0c;数据类型自定义 1.2、序列延申1.2.1、理论1.2.2、测试1.2.3、小结 二、函数2.1、SQL直接创建2.1.1…

20240108移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通的步骤

20240108移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通的步骤 2024/1/8 17:50 缘起&#xff1a;使用友善之臂的Android11可以让EC20上网&#xff0c;但是同样的修改步骤&#xff0c;Toybrick的Android11不能让EC20上网。最后确认是selinux的问题&#xff01; …

DDIM学习笔记

写在前面&#xff1a; &#xff08;1&#xff09;建议看这篇论文之前&#xff0c;可先看我写的前一篇论文&#xff1a; DDPM推导笔记-大白话推导 主要学习和参考了以下文章&#xff1a; &#xff08;1&#xff09;一文带你看懂DDPM和DDIM &#xff08;2&#xff09;关于 DDIM …

如何优雅的搭建一个轻量化的网站

本地网页 这里我找到了一个带有简单的悬停变色效果的个人博客网站模板。用来演示这次的轻量化网站搭建。你可以复制这段代码到一个txt文件中&#xff0c;修改文件后缀名为html即可得到一个最简单的静态网页文件。在没有搭建网站服务器时&#xff0c;本机可以通过直接双击该文件…

设计模式的艺术P1基础—2.3 类之间的关系

设计模式的艺术P1基础—2.3 类之间的关系 在软件系统中&#xff0c;类并不是孤立存在的&#xff0c;类与类之间存在各种关系。对于不同类型的关系&#xff0c;UML提供了不同的表示方式 1&#xff0e;关联关系 关联&#xff08;Association&#xff09;关系是类与类之间最常用…