【鸿蒙应用ArkTS开发系列】-自定义底部菜单列表弹窗

文章目录

  • 前言
  • 创建Demo工程
    • 创建dialog 文件夹
    • 创建ListMenu 接口
    • 创建自定义弹窗 ListMenuDialog
    • 使用自定义弹窗
  • 打包测试
  • 效果演示
    • 默认效果
    • 菜单带图标效果
    • 设置文本颜色效果
    • 不同文本颜色效果
    • 无标题效果

前言

上一篇文章中我们实现了选择图片、选择文件、拍照的功能 。
链接在这里,大家有兴趣可以点击 《【鸿蒙应用ArkTS开发系列】- 选择图片、文件和拍照功能实现》 。

之前的效果
在这里插入图片描述
这一节我们要实现的效果
在这里插入图片描述

上一节 我们是在页面布局中使用三个按钮来作为入口,但是有些场景,我们希望应用以底部菜单弹窗的形式来与用户进行操作交互。那在鸿蒙原生应用中,一个自定义的底部菜单列表弹窗应该怎么实现呢,这一节,我们来讲下这个基础知识。

创建Demo工程

我们使用Empty Ability 模板创建一个Demo工程。
在这里插入图片描述
在这里插入图片描述

创建dialog 文件夹

在这里插入图片描述

创建ListMenu 接口

在src->main->ets ->dialog 文件夹下创建ListMenu.ets文件,完整代码如下:

/**
 * 菜单
 */
export interface ListMenu {
  id: string;
  text: string | Resource;
  icon?: Resource;
  fontColor?: ResourceColor;
  onItemClick?: () => void;
}

这里我们对底部菜单列表的菜单选项数据进行抽象,抽取出通用字段:

  • id 唯一字段
  • text 显示的菜单文本
  • icon 文本左侧显示的图标,非必传
  • fontColor 文本颜色 非必传
  • onItemClick 点击事件

下面我们来看下自定义弹窗类的代码实现。

创建自定义弹窗 ListMenuDialog

在src->main->ets ->dialog 文件夹下创建ListMenuDialog.ets文件,完整代码如下:

/**
 * 自定义底部列表菜单弹窗
 */
import { ListMenu } from './ListMenu';

@CustomDialog
export struct ListMenuDialog {
  @Prop title: string = '';
  @State titleVisible: boolean = true;
  @State menuArray: ListMenu[] = [];
  controller: CustomDialogController;
  onCancel?: () => void;

  @Styles
  itemPressedStyle() {
    .backgroundColor('#e2e2e2')
  }

  @Styles
  itemNormalStyle() {
    .backgroundColor(Color.White)
  }

  build() {
    Column() {
      Text(this.title)
        .fontColor('#999999')
        .fontSize(14)
        .margin({ top: 10 })
        .maxLines(1)
        .visibility(this.titleVisible ? Visibility.Visible : Visibility.None)

      if (this.menuArray.length > 0) {

        Scroll() {
          Column() {
            ForEach(this.menuArray, (item: ListMenu, index: number) => {

              this.MenuItem(item, index)

            }, (index: number) => {
              return index.toString();
            })
          }
        }
        .backgroundColor(Color.White)
        .borderRadius(8)
        .margin({ top: 10 })
        .constraintSize({
          maxHeight: '40%'
        })
      }

      Text('取消')
        .width('100%')
        .height(50)
        .fontColor(Color.Black)
        .fontSize(16)
        .margin({ top: 15 })
        .backgroundColor(Color.White)
        .textAlign(TextAlign.Center)
        .borderRadius(8)
        .stateStyles({
          normal: this.itemNormalStyle,
          pressed: this.itemPressedStyle
        })
        .onClick(() => {
          if (this.controller) {
            this.controller.close();
          }
          if (this.onCancel) {
            this.onCancel();
          }
        })
    }
    .padding(10)
    .alignItems(HorizontalAlign.Center)
    .width('100%')
    .backgroundColor('#f8f8f8')
    .borderRadius({
      topLeft: 15,
      topRight: 15
    })

  }

  @Builder
  MenuItem(item: ListMenu, index: number) {
    Row() {

      Image(item.icon)
        .width(30)
        .height(30)
        .visibility(item.icon ? Visibility.Visible : Visibility.None)

      Text(item.text)
        .fontColor(item.fontColor ? item.fontColor : Color.Black)
        .fontSize(16)
        .textAlign(TextAlign.Center)
        .margin({ left: 5 })
    }
    .width('100%')
    .height(50)
    .alignItems(VerticalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .borderStyle({ bottom: BorderStyle.Solid })
    .borderColor('#f8f8f8')
    .borderWidth({
      bottom: index === this.menuArray.length - 1 ? 0 : 1
    })
    .stateStyles({
      normal: this.itemNormalStyle,
      pressed: this.itemPressedStyle
    })
    .onClick(() => {
      if (this.controller) {
        this.controller.close();
      }
      if (item.onItemClick) {
        item.onItemClick();
      }
    })
  }
}


下面我们对这个自定义弹窗代码进行一些讲解:

  1. 首先我们定义一个ListMenuDialog 的结构体;
    export struct ListMenuDialog 。

  2. 使用@CustomDialog装饰器
    我们使用@CustomDialog装饰这个ListMenuDialog 结构体,表明我们这个结构体是一个自定义对话框。

  3. 定义自定义弹窗控制器CustomDialogController
    通过定义CustomDialogController,在弹窗内部可以触发弹窗的打开跟关闭。

  4. title
    弹窗标题,这里定义为Prop, 可以与页面进行状态同步,对于有弹窗标题动态修改的场景,可以使用到。

  5. titleVisible
    控制标题是否显示,如果弹窗没有标题,通过传递false进行设置标题不显示。

  6. menuArray
    列表菜单数据源 ,通过使用ForEach进行遍历调用 我们MenuItem子项 绘制列表UI。

  7. MenuItem
    这个是菜单项UI布局方法,我们使用@Builder装饰。

  8. 分隔线
    通过给Item设置 border,绘制底部边框来实现分隔线的效果。

  9. 菜单按下点击色
    通过设置 stateStyles,给Item配置两个@Style装饰的样式itemNormalStyle 跟itemPressedStyle,来实现按下Item显示一个点击效果。

这样我们就完成了一个自定义底部菜单列表弹窗,下面我们在页面中来进行实际使用。

使用自定义弹窗

我们在Index.ets 中添加如下代码:

import { ListMenu } from '../dialog/ListMenu';
import { ListMenuDialog } from '../dialog/ListMenuDialog';

@Entry
@Component
struct Index {
  @State message: string = '点击弹窗';
  private customDialogController: CustomDialogController;

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(this.showBottomDialog.bind(this))
      }
      .width('100%')
    }
    .height('100%')
  }

  showBottomDialog() {
    const menuList: ListMenu[] = [
      {
        id: '1',
        text: '选择图片',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了选择图片');
        }
      },
      {
        id: '2',
        text: '选择文件',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了选择文件');
        }
      },
      {
        id: '3',
        text: '拍照',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了拍照');
        }
      },
    ];

    this.customDialogController = new CustomDialogController({
      builder: ListMenuDialog(
        {
          title: '多媒体操作',
          menuArray: menuList,
          controller: this.customDialogController
        }),
      cancel: () => {
        console.log('点击了取消');
      },
      autoCancel: true,
      alignment: DialogAlignment.Bottom,
      customStyle: true
    });
    this.customDialogController.open();
  }

  hideBottomDialog() {
    this.customDialogController.close();
  }
}

我们定义了一个CustomDialogController 弹窗控制器,这里我们对CustomDialogController的一些属性进行下讲解,

  • builder:
    这个是设置一个@CustomDialog装饰的弹窗对象,这里使用我们上面创建的ListMenuDialog自定义弹窗。
  • cancel:
    这个是弹窗取消时候会触发的回调函数。
  • autoCancel:
    true 可以通过触击弹窗外空白处使得弹窗关闭,false ,则不可以。
  • alignment:
    这个是弹窗的显示位置,这里我们设置为DialogAlignment.Bottom,在底部弹出。
  • customStyle :
    这个是是否自定义弹窗样式,我们是自定义弹窗,设置为true即可。

我们通过构建一个弹窗控制器来控制弹窗的显示跟关闭,通过构建ListMenuDialog对象来配置弹窗数据源和显示样式,包括标题,标题是否显示,弹窗菜单的样式。 那接下来我们直接运行demo看下效果。

打包测试

打包安装到真机上,需要我们给项目配置签名信息。我们点击File -> Project Structure ->Project ,选择 Signing Configs面板,勾选 Support HarmonyOS 跟Automatically generate signature,自动生成调试签名,生成完毕后,运行安装到手机上。

效果演示

默认效果

const menuList: ListMenu[] = [
      {
        id: '1',
        text: '选择图片',
        fontColor: $r("app.color.blue_089ed9")
      },

在这里插入图片描述

菜单带图标效果

const menuList: ListMenu[] = [
      {
        id: '1',
        text: '选择图片',
        icon: $r('app.media.ic_picture'),
        onItemClick: () => {
          console.log('点击了选择图片');
        }
      },
      {
        id: '2',
        text: '选择文件',
        icon: $r('app.media.ic_file'),
        onItemClick: () => {
          console.log('点击了选择文件');
        }
      }
 ]

在这里插入图片描述

设置文本颜色效果

在这里插入图片描述

const menuList: ListMenu[] = [
      {
        id: '1',
        text: '选择图片',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了选择图片');
        }
      },
      {
        id: '2',
        text: '选择文件',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了选择文件');
        }
      }
]

不同文本颜色效果

const menuList: ListMenu[] = [
      {
        id: '1',
        text: '选择图片',
        fontColor: $r("app.color.blue_089ed9"),
        onItemClick: () => {
          console.log('点击了选择图片');
        }
      },
      {
        id: '2',
        text: '选择文件',
        fontColor: $r("app.color.green_2f7e04"),
        onItemClick: () => {
          console.log('点击了选择文件');
        }
      }
]

在这里插入图片描述

无标题效果

 builder: ListMenuDialog(
        {
          menuArray: menuList,
          controller: this.customDialogController
        }),

在这里插入图片描述

大家也可以 在 ListMenu中增加一些其他的字段属性来拓展弹窗样式,比如图标的大小、文本的对齐方式等等。

那本章内容就到此结束,谢谢大家的阅读! 有疑问的可以在评论区留言交流。

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

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

相关文章

【网络协议】聊聊网络ReadTimeout和ConnectTimeout

在实际的开发中,网络超时是一个比较常见的问题,比如说针对支付系统,超时就需要进行和三方人员进行核对订单状态,是否人工介入处理。 但其实在设计网络框架的时候,一般都有两个超时参数 连接超时参数 ConnectTimeout&am…

阻抗匹配电阻原理及其应用

一、匹配电阻的作用 1、阻抗匹配 当信号频率比较高,上升沿比较陡时,电子信号经过阻抗不同的地方时也会产设反射。 PCB的单线阻抗一般会设计成50Ω,发射端阻抗一般是17到40,而接收端一般是MOS管的输入,阻抗是比较大的…

Python 高性能 web 框架 - FastApi 全面指南

原文:Python 高性能 web 框架 - FastApi 全面指南 - 知乎 一、简介 FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.6 并基于标准的 Python 类型提示。 它具有如下这些优点: 快速&…

shell编程系列(11)-使用grep查找文本

文章目录 前言grep的使用根据关键字查找反向查找 结语 前言 grep命令也是我们在日常使用linux,编写shell脚本中会用到的一个高频命令,grep主要是帮助我们查找我们想要的内容,类似于我们在office word里面的 Ctrl f 查找功能,但是…

LabVIEW在不同操作系统上使VI、可执行文件或安装程序

LabVIEW在不同操作系统上使VI、可执行文件或安装程序 LabVIEW可以在多个操作系统上运行,主要支持以下几种操作系统: Windows: LabVIEW在各个版本的Windows操作系统上都能运行,包括Windows 7、Windows 8和Windows10。LabVIEW为Wi…

docker容器中创建非root用户

简介 用 docker 也有一段时间了,一直在 docker 容器中使用 root 用户肆意操作。直到部署 stable diffusion webui 我才发现无法使用 root 用户运行它,于是才幡然醒悟:是时候搞个非 root 用户了。 我使用的 docker 镜像文件是 centos:centos…

使用系统ProgressBar实现三色进度条

使用系统ProgressBar实现如图三色进度条&#xff1a; //布局中<ProgressBarandroid:layout_width"0dp"android:layout_height"8dp"android:layout_marginLeft"16dp"app:layout_constraintBottom_toBottomOf"id/photo"app:layout_c…

解决报错:error: (-215:Assertion failed) inv_scale_x > 0 in function ‘cv::resize‘

需求背景 欲使用opencv的resize函数将图像沿着纵轴放大一倍&#xff0c;即原来的图像大小为(384, 512), 现在需要将图像放大为(768, 512)。 源码 import cv2 import numpy as np# 生成初始图像 img np.zeros((384, 512), dtypenp.uint8) img[172:212, 32:-32] 255 H, W …

Python爬虫教程27:秀啊!用Pandas 也能爬虫??

说到爬虫&#xff0c;大家可能都知道requests、re、scrapy、selenium等等一些工具库。虽然它低调&#xff0c;但功能非常强大&#xff0c;用于抓取Table表格型数据时&#xff0c;简直是个神器&#xff0c;没有必要去F12研究HTML页面结构甚至写正则表达式解析字段。 #我的Pytho…

Python教程78:聊聊exec和eval()函数,有什么用法区别

exec 和 eval 是 Python 中的两个内置函数&#xff0c;它们都可以执行Python代码&#xff0c;但它们的使用方式和目的有所不同。 1.exec()函数用于执行动态的 Python 代码&#xff0c;你可以使用exec来执行存储在字符串或对象代码中的 Python 代码。exec 不会返回任何结果&…

Python遥感开发之批量镶嵌

Python遥感开发之批量镶嵌 1.ArcGis镶嵌2.Arcpy实现镶嵌2.1 Arcpy实现单个镶嵌2.2 Arcpy实现批量镶嵌 3.GDAL实现镶嵌 前言&#xff1a;主要介绍了遥感数据的镶嵌&#xff0c;其中包括使用ArcGis如何完成镶嵌&#xff0c;如何使用Arcpy和GDAL完成镶嵌。 1.ArcGis镶嵌 是ArcGis…

记一次若依二开的简单流程

记一次若依二开的简单流程 前言: 搞Java后端的应该都知道若依框架&#xff0c;是一个十分强大且功能齐全的开源的快速开发平台&#xff0c;且毫无保留给个人及企业免费使用。很多中小型公司会直接在该系统上进行二次开发使用。本文记录一次使用若依二开零编码的简单实现&#…

Fiddler抓包工具之fiddler设置断点和简单的并发测试

断点有两种方式&#xff1a; 1、全局断点 2、局部断点 全局断点 全局断点的特点是&#xff1a;不能针对一个请求&#xff0c;是给所有抓到的请求打断点 全局断点如何设置&#xff1a; 1、快速设置断点&#xff1a;直接点击底部状态栏断点处 &#xff1b;点击第一下是请求…

vcruntime140.dll无法继续执行代码五种解决方法修复教程

在电脑使用过程中&#xff0c;我们可能会遇到一些常见的错误提示&#xff0c;其中之一就是“vcruntime140.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。本文将介绍vcruntime140.dll丢失对电脑的影响以及如何修复这个问题&#xff0c;并提供一些预防措施&#xff0…

Ubuntu系统CLion安装与Ubuntu下菜单启动图标设置

Ubuntu系统CLion安装 pycharm 同理。 参考官网安装过程&#xff1a;官网安装过程 下载linux tar.gz包 # 解压 sudo tar -xzvf CLion-*.tar.gz -C /opt/ sh /opt/clion-*/bin/clion.sh其中第二个命令是启动CLion命令 clion安装完以后&#xff0c;不会在桌面或者菜单栏建立图…

半监督语义分割综述

paper link&#xff1a;https://arxiv.org/pdf/2302.09899.pdf 1. Introduction 图像分割是最古老、研究最广泛的计算机视觉 (CV) 问题之一。图像分割是指将图像划分为不同的非重叠区域&#xff0c;并将相应的标签分配给图像中的每个像素&#xff0c;最终获得ROI区域位置及其类…

Linux - 动态库的加载 和 重谈进程地址空间 - vscode 当中的 Remote - SSH 插件

推书&#xff1a;《现代操作系统》《操作系统--精髓于设计原理》《UNIX环境高级编程》 目录 前言 程序的加载 程序没有加载之前的地址&#xff08;此时还是程序&#xff09; 程序被加载到内存之后&#xff08;此时是进程&#xff09; 动态库的地址 静态库的不加载&#xff…

海外之路,英语相助:我的雅思考试之旅(成功以此申请到了港科大硕士)

文章目录 背景注册过程 雅思考试之旅全程记录2023年2月14日 - 报名补充2023年2月15日 - 模拟考试2023年2月16日 - 在线考试失利2023年2月20日 - 线下考试再战成功2023年2月23日 - 成绩出来了 考试经验寄送成绩问题请求额外的IELTS成绩寄送 结语 背景 在新加坡Shopee工作了两年…

Linux 内核源码各版本下载

下载地址&#xff1a; kernel/git/stable/linux.git - Linux kernel stable treehttps://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/refs/ 1. Linux 内核的基本概念&#xff1a; 内核是什么&#xff1f; 内核是操作系统的核心部分&#xff0c;负责管理系统…

Active Stereo Without Pattern Projector论文精读

1.背景补充 主动立体相机和被动立体相机的主要区别在于它们获取立体视觉信息的方式 主动立体相机12&#xff1a; 主动立体视觉是指寻找最佳的视角去重建目标或者场景1。主动视觉的实现方式通常有&#xff1a;改变环境中的光照条件、改变相机的视角、移动相机自身位置等&…