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

news2024/10/7 14:26:43

文章目录

  • 前言
  • 创建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中增加一些其他的字段属性来拓展弹窗样式,比如图标的大小、文本的对齐方式等等。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11.28 C++作业

提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream>using namespace std;int main() {string str;cout << "请输入一个字符串&#xff1a;" <<…

92基于matlab的引力搜索算法优化支持向量机(GSA-SVM)分类模型

基于matlab的引力搜索算法优化支持向量机&#xff08;GSA-SVM&#xff09;分类模型&#xff0c;以分类精度为优化目标优化SVM算法的参数c和g&#xff0c;输出分类可视化结果及适应度变化曲线。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 92 引力搜索算法…

无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv5开发构建电力设备螺母缺销小目标检测识别系统

传统作业场景下电力设备的运维和维护都是人工来完成的&#xff0c;随着现代技术科技手段的不断发展&#xff0c;基于无人机航拍飞行的自动智能化电力设备问题检测成为了一种可行的手段&#xff0c;本文的核心内容就是基于YOLOv7来开发构建电力设备螺母缺销检测识别系统&#xf…

Symbol()和迭代器生成器

目录 1、Symbol&#xff08;&#xff09; 2、迭代器生成器 执行流程 模拟生成器函数 for of 遍历迭代选择器 yield * Generator函数应用 1、Symbol&#xff08;&#xff09; Symbol表示独一无二的值 const s1 Symbol(a)const s2 Symbol(a)console.log(s1 s2) // fa…

PCB走线宽度与电流的关系表

在1 oz./sq. ft.铜重量时将温度上升限制在10C。这应该可以让您大致了解如何调整PCB中的走线尺寸。 电流&#xff08;A&#xff09;走线宽度&#xff08;mil&#xff09;1102303504805110615071808220926010300 上表适用于许多通常采用标准工艺生产的PCB&#xff0c;其目标是非…

SHAP(三):在解释预测模型以寻求因果见解时要小心

SHAP&#xff08;三&#xff09;&#xff1a;在解释预测模型以寻求因果见解时要小心 与 Microsoft 的 Eleanor Dillon、Jacob LaRiviere、Scott Lundberg、Jonathan Roth 和 Vasilis Syrgkanis 合作撰写的关于因果关系和可解释机器学习的文章。 当与 SHAP 等可解释性工具配合…

STM32CubeMx+MATLAB Simulink点灯程序

STM32CubeMxMATLAB点灯程序 ✨要想实现在MATLAB Simulink环境下使用STM32&#xff0c;前提是已经搭建好MATLAB环境并且安装了必要的Simulink插件&#xff0c;以及对应的STM32支持包。 &#x1f33f;需要准备一块所安装支持包支持的STM32开发板. &#x1f516;具体支持包详情页…

uniapp uni-popup组件在微信小程序中滚动穿透问题

起因 在微信小程序中使用uni-popup组件时&#xff0c;出现滚动穿透&#xff0c;并且uni-popup内部内容不会滚动问题。 解决 滚动穿透 查阅官方文档&#xff0c;发现滚动穿透是由于平台差异性造成的&#xff0c;具体解决可以参照文档禁止滚动穿透 <template><page-…

Chrome 拓展开发系列:什么是 Chrome 拓展?

文章目录 Chrome 拓展&#xff08;Chrome Extension&#xff09;是什么为什么使用 Chrome 拓展&#xff1f;个性化浏览体验提高工作效率改善隐私和安全创新新功能 发展历史2009 年&#xff1a;初版发布2010 年&#xff1a;稳步增长2013 年&#xff1a;Chrome App 和扩展合并201…

企业存货库存综合分析全流程图

上期我们谈到了 诊断存货管理的4大维度&#xff0c;今天我们进一步全方位、全周期的分析企业内存货的问题。 企业存货是企业用于生产或销售的货品&#xff0c;是企业价值增值变现的载体&#xff0c;但是如果一旦没有产生交易&#xff0c;存货就很有可能带来损失。存货伴随着企业…

反序列化漏洞详解(一)

目录 一、php面向对象 二、类 2.1 类的定义 2.2 类的修饰符介绍 三、序列化 3.1 序列化的作用 3.2 序列化之后的表达方式/格式 ① 简单序列化 ② 数组序列化 ③ 对象序列化 ④ 私有修饰符序列化 ⑤ 保护修饰符序列化 ⑥ 成员属性调用对象 序列化 四、反序列化 …

深度学习今年来经典模型优缺点总结,包括卷积、循环卷积、Transformer、LSTM、GANs等

文章目录 1、卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;1.1 优点1.2 缺点1.3 应用场景1.4 网络图 2、循环神经网络&#xff08;Recurrent Neural Networks&#xff0c;RNNs&#xff09;2.1 优点2.2 缺点2.3 应用场景2.4 网络图 3、长短…

ZeroTier外网访问实验室Linux服务器

ZeroTier外网访问实验室Linux服务器 1、在ZeroTier上创建一个自己的Network 进入ZeroTier的官网https://www.zerotier.com/注册一个账号 注册完之后登录进去&#xff0c;创建自己的Network 创建完之后来到IPv4的分配管理&#xff0c;选择主机位只有后8位的IP&#xff0c;才能…

Windows安装Mysql Workbench及常用操作

Mysql Workbench是mysql自带的可视化操作界面&#xff0c;功能是强大的&#xff0c;但界面和navicat比&#xff0c;就是觉得别扭&#xff0c;但其实用惯了也还好&#xff0c;各有特色吧。这里记录一下常用的操作。 官方手册&#xff1a;MySQL Workbench 一、安装 1. 下载 官方…

C++可表示的数(数组前面2个数的和)

void 可表示的数&#xff08;数组前面2个数的和&#xff09;() {int aa[]{1,2,3,4,5,6,7,8,9}, j 0, z 1, jj z, n 9, ge 0;string a "";while (j < n)//缘由https://bbs.csdn.net/topics/396063706?page1#post-410898529{if (jj < n)if (aa[j] aa[z] …

深入浅出强化学习

目录 一、强化学习的概念 二、强化学习的特点 三、强化学习的训练过程 一、强化学习的概念 强化学习是一种机器学习方法&#xff0c;旨在教会算法如何通过与环境的交互来进行学习和决策。与传统的监督学习和无监督学习不同&#xff0c;强化学习侧重于学习与奖励和惩罚&#…

OSI七层模型的前三层

开发中我们常见的网络设计和网络排查等&#xff0c;用到的网络层一般是tcp/ip第四层&#xff0c;也称OSI 网络层&#xff0c;很少去关心前三层的网络层、数据链路层、物理层&#xff0c;脑海里想到这三层的数据流转&#xff0c;脑海里都是抽象的画面。 本篇浅显的梳理前三层中各…

spring boot 3.2.0 idea从零开始

spring boot 3.2.0 idea从零开始 最新的spring initilizer 不再支持低版本java&#xff0c;只能选择17、21 。 我也被迫尝试下最新版本的java。 jdk下载地址 自定义好artifact和group之后点击下一步。 在这里选择需要的组件&#xff0c;我准备做web项目所以只选择spring web …

Navicat Premium 16.3.3 Windows x64 Crack

增强您的表现。 Navicat 16 具有许多改进和功能&#xff0c;可以满足您的数据库开发需求。凭借 100 多项增强功能和全新界面&#xff0c;您可以探索构建、管理和维护数据库的新方法。构建时考虑到可用性。 Navicat 16 引入了许多 UI/UX 改进&#xff0c;以最大限度地提高您的效…

C++浅谈Actor模型及其应用

文章目录 0 引入1、理解1.1 为什么会出现Actor这种模型呢&#xff1f;1.2 Actor如何解决 2、应用1.SkyNet2.Erlang3.RabbitMQ 3、引用 0 引入 最近发现Actor模型其实我在工作中已经不知不觉实现了&#xff0c;最起码有这些影子。 1、理解 Actor模型是一种轻量级的并发编程模型…