鸿蒙开发(八)添加常用控件(下)

news2024/12/28 5:11:18

    添加控件的文章分成了上下两篇,上篇介绍了文本显示、文本输入、按钮、图片、单选框、切换按钮这六种常用控件,本篇继续介绍其他几种很重要但略微复杂的控件。

鸿蒙系列上一篇:

鸿蒙开发(七)添加常用控件(上)-CSDN博客文章浏览阅读673次,点赞19次,收藏15次。相信大家已经对鸿蒙开发的布局有了基本的了解。之前我们提到过,一个好的UI,离不开选择合理的布局。当然,也离不开适当的控件。本篇文章,带着大家一起学习下如何在页面里面添加常用的控件。由于控件较多,我会分为两篇文章来介绍。https://blog.csdn.net/qq_21154101/article/details/135747069?spm=1001.2014.3001.5501

目录

一、进度条(Progress)

1、线性样式

2、环形无刻度样式

3、环形有刻度样式

4、圆形样式

5、胶囊进度条 

二、自定义弹窗(CustomDialog)

1、创建自定义弹窗

2、展现弹窗和监听事件

三、视频(Video)

1、播放本地视频

2、播放沙箱视频 

3、播放网络视频

四、气泡(Popup)

1、系统气泡

2、自定义气泡 

(1)创建自定义气泡

(2)绑定自定义气泡

五、菜单(Menu)

1、默认菜单

2、自定义菜单

3、支持长按的菜单 


一、进度条(Progress)

    进度条是我们日常开发中经常使用的一种控件,用于显示某种操作的进度,给用户以友好的提示,Progress是进度条显示组件。使用如下方法创建:

Progress(options: {value: number, total?: number, type?: ProgressType})

    value为进度条的进度,total为进度的最大值,type为进度条的类型,支持如下几种类型:

ProgressType.Linear线型样式
ProgressType.Ring环形无刻度样式
ProgressType.ScaleRing环形有刻度样式
ProgressType.Eclipse圆形样式
ProgressType.Capsule胶囊样式

1、线性样式

    ProgressType.Linear创建线性样式进度条,线性样式的进度条默认水平展示,高度大于宽度的时候会自适应垂直显示:

// 线性样式的进度条
Progress({ value: 25, total: 100, type: ProgressType.Linear })
    .width('80%')

2、环形无刻度样式

    ProgressType.Ring创建环形无刻度样式进度条:

// 环形无刻度进度条
Progress({ value: 25, total: 100, type: ProgressType.Ring })

3、环形有刻度样式

    ProgressType.ScaleRing创建环形有刻度样式进度条,环形有刻度样式进度条需要设置style属性,否则跟环形无刻度进度条一样,看不出效果:

// 环形有刻度进度条
Progress({ value: 25, total: 100, type: ProgressType.ScaleRing })
    .style({ scaleCount: 20, scaleWidth: 3, strokeWidth: 10 }) // 20刻度,刻度宽度3,刻度长度10

4、圆形样式

    ProgressType.Eclipse创建圆形样式进度条:

// 圆形进度条
Progress({ value: 25, total: 100, type: ProgressType.Eclipse })

5、胶囊进度条 

    ProgressType.Capsule创建圆形样式进度条,需要设置宽高否则跟圆形样式一样,且宽>高时水平展示,高>宽时垂直展示:

// 胶囊进度条
Progress({ value: 25, total: 100, type: ProgressType.Capsule })
    .width(50)
    .height(100)

    实现一个demo,使用一个Button控制进度条的进度,如下完整代码:

@Entry
@Component
struct AddWidget2 {
  @State progress: number = 5

  build() {
    Row() {
      Column() {
        // 线性样式的进度条
        Progress({ value: this.progress, total: 100, type: ProgressType.Linear })
          .width('80%')
        Row() {
          // 环形无刻度进度条
          Progress({ value: this.progress, total: 100, type: ProgressType.Ring })
          // 环形有刻度进度条
          Progress({ value: this.progress, total: 100, type: ProgressType.ScaleRing })
            .style({ scaleCount: 20, scaleWidth: 3, strokeWidth: 10 }) // 20刻度,刻度宽度3,刻度长度10
            .backgroundColor(Color.Gray) // 背景颜色灰色
            .color(Color.Black) // 进度颜色黑色
          // 圆形进度条
          Progress({ value: this.progress, total: 100, type: ProgressType.Eclipse })
          // 胶囊进度条
          Progress({ value: this.progress, total: 100, type: ProgressType.Capsule })
            .width(50)
            .height(100)
        }.width('100%').justifyContent(FlexAlign.SpaceEvenly)

        Button('进度+5')
          .onClick(() => {
            this.progress += 5
            if (this.progress > 100) {
              this.progress = 0
            }
          })

      }
      .width('100%')
      .margin({ top: 20 })
    }
  }
}

     如下是上述代码的效果:

二、自定义弹窗(CustomDialog)

    自定义弹窗(CustomDialog)主要用来给用户提示或警告用的。比如删除文件的二次确认,比如即将跳转某个页面的提示等,也可以用于广告、抽奖、签到等场景。

    CustomDialog的使用与之前的控件有点区别。从名字也可以看出,既然是自定义弹窗,那么自然需要自定义一个控件,使用方式如下:

1、使用@CustomDialog装饰器装饰自定义弹窗

2、通过CustomDialogController类显示自定义弹窗

    接下来,通过实现一个小demo来看下CustomDialog如何创建,并且实现对弹窗内部事件的监听和分发。demo效果如下:

1、创建自定义弹窗

    在页面里面新建一个struct - MyDialog,创建自定义弹窗需要使用@CustomDialog注解修饰struct,如下所示:

@CustomDialog
struct MyDialog {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void

  build() {
    Column() {
      Text('确定要删除文件吗')
        .fontSize(20)
        .margin({ top: 20, bottom: 40 })
      Row() {
        Button('确认')
          .onClick(() => {
            this.controller.close()
            this.confirm()
          })
        Button('取消')
          .onClick(() => {
            this.controller.close()
            this.cancel()
          })
      }.width('75%').justifyContent(FlexAlign.SpaceAround).margin({ bottom: 20 })
    }
  }
}

     简单解释下如上代码: 

1、CustomDialogController用来控制弹窗的展现和消失。

2、两个接口cancel和confirm,分别用来监听和分发"确认"和"取消"两个按钮的点击事件。

3、布局内容也很简单,上面一个Text,下面两个Button,整个窗体占据75%的屏幕宽度。

2、展现弹窗和监听事件

    接下来,在页面中通过点击一个按钮去展现上面自定义的弹窗,并且分别监听其确认和取消按钮的点击事件。代码如下:

@Entry
@Component
struct AddWidget2 {
  @State progress: number = 5
  dialogController: CustomDialogController = new CustomDialogController({
    builder: MyDialog({
      cancel: this.onCancel,
      confirm: this.onConfirm
    }),
    alignment: DialogAlignment.Default
  })

  onCancel() {
    promptAction.showToast({ message: '点击了取消' })
  }

  onConfirm() {
    promptAction.showToast({ message: '点击了确认' })
  }

  build() {
    Row() {
      Column() {
        Button('弹窗')
          .onClick(() => {
            this.dialogController.open()
          }).margin({ top: 10 })

      }
      .width('100%')
      .margin({ top: 20 })
    }
  }

    最后,看下效果:

注:本篇的代码都在同一个页面AddWidget2里面写的,贴的上述代码我把上一节中进度条的代码给删掉了,但是最终的演示效果仍然是所有的代码,不要疑惑为什么我的页面上方多了那么多进度条。

三、视频(Video)

    视频的场景更为广泛,前几年短视频兴起后,抖音、快手等短视频app都用到了视频播放组件。Video组件的使用方式如下:

Video(value: {src?: string | Resource, currentProgressRate?: number | string | PlaybackSpeed, previewUri?: string | PixelMap | Resource, controller?: VideoController})

    其中,src指定视频播放源的路径,currentProgressRate用于设置视频播放倍速,previewUri指定视频的封面图路径,controller设置视频控制器,用于自定义控制视频。

1、播放本地视频

    加载本地视频时,首先在本地rawfile目录指定对应的文件,如下图所示:

    再使用资源访问符$rawfile()引用视频资源。

@Component
export struct VideoPlayer{
   private controller:VideoController;
   private previewUris: Resource = $r ('app.media.preview');
   private innerResource: Resource = $rawfile('test.mp4');
   build(){
     Column() {
       Video({
         src: this.innerResource,
         previewUri: this.previewUris,
         controller: this.controller
       })
   }
 }
}

2、播放沙箱视频 

    支持file:///data/storage路径前缀的字符串,用于读取应用沙箱路径内的资源。需要保证应用沙箱目录路径下的文件存在并且有可读权限。

@Component
export struct VideoPlayer {
  private controller: VideoController;
  private videoSrc: string = 'file:///data/storage/el2/base/haps/entry/files/show.mp4'

  build() {
    Column() {
      Video({
        src: this.videoSrc,
        controller: this.controller
      })
    }
  }
}

3、播放网络视频

    日常开发中最常用的应该还是播放网络视频。加载网络视频时,需要申请权限ohos.permission.INTERNET:

@Component
export struct VideoPlayer{
   private controller:VideoController;
   private previewUris: Resource = $r ('app.media.preview');
   private videoSrc: string= 'https://www.example.com/example.mp4' 
   build(){
     Column() {
       Video({
         src: this.videoSrc,
         previewUri: this.previewUris,
         controller: this.controller
       })
   }
 }
}

    通过加载以上三种路径的视频可以看出,调用的都是同样的方法,只不过videoSrc不同。接下来,通过如下代码加载一个本地视频:

        Video({
          previewUri: ($r('app.media.icon')),
          src: ($rawfile('test.mp4')),
          controller: this.controller
        })
          .autoPlay(true)
          .muted(true)
          .loop(true)
          .onStart(() => {
            promptAction.showToast({ message: '开始播放' })
          })
          .onPause(() => {
            promptAction.showToast({ message: '暂停播放' })
          })
          .onFinish(() => {
            promptAction.showToast({ message: '结束播放' })
          })
          .width('90%')
          .height('25%')
          .margin({ top: 20 })

     来看下效果(吐槽一下:鸿蒙的模拟器真的太卡了,为了录个屏模拟器重启和清数据了好几次,唉.....就这还打造屁的生态):

四、气泡(Popup)

    气泡是一个比较特殊的控件,因为它需要作为属性去绑定到其他的组件上,在组件上显示气泡弹窗提示。气泡分为两种类型,一种是系统气泡,一种是自定义气泡。

1、系统气泡

    PopupOptions为系统提供的气泡,可以通过配置primaryButton、secondaryButton来设置带按钮的气泡,跟用户做简单的交互。如下:

  @State bindPop: boolean = false
        // 气泡
        Text('测试气泡用的文本框')
          .onClick(() => {
            this.bindPop = !this.bindPop
          })
          .borderWidth(1)
          .padding(4)
          .margin({ top: 10 })
          .bindPopup(this.bindPop, { message: '这里是气泡',
            onStateChange: (event) => {
              if (event.isVisible) {
                promptAction.showToast({ message: '气泡可见' })
              } else {
                promptAction.showToast({ message: '气泡消失' })
              }
            },
            primaryButton: {
              value: '确定',
              action: () => {
                this.bindPop = false
              }
            },
            secondaryButton: {
              value: '取消',
              action: () => {
                this.bindPop = false
              }
            }})

 1、定义了一个@State变量bindPop,用来通过其变化即时刷新气泡显示与隐藏

2、增加了状态监听onStateChange,并且弹toast告诉我们是显示还是隐藏

3、增加了两个按钮,点击时控制气泡消失

    看下效果:

2、自定义气泡 

    可以使用构建器创建自定义气泡,@Builder中可以放自定义的内容。除此之外,还可以通过popupColor等参数控制气泡样式。

(1)创建自定义气泡

    使用@Builder注解创建自定义气泡,并且实现自定义的布局和控件,如下代码:

  @Builder
  popupBuilder() {
    Column() {
      Row() {
        Image($r("app.media.icon"))
          .width(24)
          .height(24)
          .margin({ left: 20 })
        Text('这是自定义气泡')
          .fontSize(15)
          .margin({ left: 20 })
      }.margin({ top: 20 })

      Column() {
        Button('按钮1')
          .margin({ top: 10 })
          .onClick(() => {
            promptAction.showToast({ message: '点击了按钮1' })
          })
        Button('按钮2')
          .margin({ top: 10 })
          .onClick(() => {
            promptAction.showToast({ message: '点击了按钮2' })
          })
        Button('按钮3')
          .margin({ top: 10 })
          .onClick(() => {
            promptAction.showToast({ message: '点击了按钮3' })
          })
      }.margin({ bottom: 20 })
    }.width('80%')
  }

(2)绑定自定义气泡

    绑定自定义气泡到控件上,实现同样跟上面系统气泡一样的显隐逻辑,代码如下:

  @State bindCustomPop: boolean = false
        // 自定义气泡
        Text('测试自定义气泡用的文本框')
          .onClick(() => {
            this.bindCustomPop = !this.bindCustomPop
          })
          .borderWidth(1)
          .padding(4)
          .margin({ top: 10 })
          .bindPopup(this.bindCustomPop, {
            builder: this.popupBuilder, // 气泡的内容
            placement: Placement.Bottom, // 气泡的弹出位置
            popupColor: Color.Gray, // 气泡的背景色
            onStateChange: (event) => {
              if (event.isVisible) {
                promptAction.showToast({ message: '气泡可见' })
              } else {
                promptAction.showToast({ message: '气泡消失' })
              }
            }
          })

    看下效果:

五、菜单(Menu)

1、默认菜单

    菜单需要调用bindMenu接口来实现,如下是使用系统默认菜单:

        // 默认菜单
        Text('测试菜单的文本框')
          .borderWidth(1)
          .padding(4)
          .margin({ top: 10 })
          .bindMenu([{ value: '菜单1'
          , action: () => {
              promptAction.showToast({ message: '菜单1' })
            } },
            { value: '菜单2'
            , action: () => {
              promptAction.showToast({ message: '菜单2' })
            } }])

2、自定义菜单

    如果系统默认的菜单样式满足不了我们的需求,可以使用@Builder自定义菜单,然后使用BindMenu(自定义Menu)的方式绑定,如下:

        // 自定义菜单
        Text('测试自定义菜单的文本框')
          .borderWidth(1)
          .padding(4)
          .margin({ top: 10 })
          .bindMenu(this.MyMenu())
      }

 

 /**
   * 自定义菜单
   */
  @Builder
  MyMenu() {
    Menu() {
      // 菜单选项1
      MenuItem({
        startIcon: $r("app.media.icon"),
        content: "菜单选项1" })
        .onChange(() => {
          promptAction.showToast({ message: "点了菜单选项1" })
        })
      // 包含两个菜单的菜单组
      MenuItemGroup({ header: '小标题' }) {
        MenuItem({ content: "菜单选项2" })
          .onChange((selected) => {
            promptAction.showToast({ message: "点了菜单选项2" })
          })
        MenuItem({ startIcon: $r("app.media.icon"), content: "菜单选项3" }).enabled(false)
      }
    }
  }

     分别看下以上两种菜单的效果:

3、支持长按的菜单 

    菜单默认是点击的方式弹出,比如我们上述使用bindMenu的方式。如果想长按触发呢?可以使用bindContextMenu设置菜单弹出的触发方式:右键或长按。我们把上述弹出自定义菜单的代码稍微修改下,如下:

        // 自定义菜单
        Text('测试自定义菜单的文本框')
          .borderWidth(1)
          .padding(4)
          .margin({ top: 10 })
          .bindContextMenu(this.MyMenu,ResponseType.LongPress)

    至此,本篇就介绍到这里了。这篇文章断断续续写了好几天,相比起上一篇添加基础控件,本篇的控件确实复杂了一些。用了两章的篇幅,我们把鸿蒙的基础系统控件都学习完了。下一篇,我们不妨一起来一次UI实战,把近期掌握的布局和控件一起在实战中检验下。

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

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

相关文章

网络安全防御保护实验(二)

一、登录进防火墙的web控制页面进行配置安全策略 登录到Web控制页面: 打开Web浏览器,输入防火墙的IP地址或主机名,然后使用正确的用户名和密码登录到防火墙的Web管理界面。通常,这些信息在防火墙设备的文档或设备上会有说明。 导…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)-机器人、强化学习

专属领域论文订阅 关注{晓理紫},每日更新论文,如感兴趣,请转发给有需要的同学,谢谢支持 如果你感觉对你有所帮助,请关注我,每日准时为你推送最新论文。 分类: 具身智能,机器人强化学习开放词汇&…

[C++开发 03_2/2 _ STL(185)]

知识点1:STL初始 概述: STL是标准模板库的意思,STL从广义上来讲分为:容器,算法,迭代器。 容器算法之间通过迭代器进行无缝连接。 知识点2:STL初始 2.1 STL诞生 C中面向对象的三大特性&#xff1…

九、Kotlin 注解

1. 什么是注解 注解是对程序的附件信息说明。 注解可以作用在类、函数、函数参数、属性等上面。 注解的信息可用于源码级、编译期、运行时。 2. 注解类的定义 使用元注解 Retention 声明注解类的作用时期。 使用元注解 Target 声明注解类的作用对象。 定义注解类时可以声…

8.6 代理设计模式

文章目录 一、代理模式(Proxy Pattern)概述二、代理模式和观察者设计模式三、模式结构四、协作角色五、实现策略六、相关模式七、示例八、应用 一、代理模式(Proxy Pattern)概述 代理模式是一种设计模式,它通过引入一个…

Windows Defender存在威胁执行操作无反应且一直存在红叉(已解决)

文章目录 前言问题如图一、原因二、解决办法(亲试有效)总结 前言 Windows安全中心(Windows Defender)执行快速扫描/完全扫描后一直存在威胁,执行隔离或者删除操作后下次扫描还会扫出该威胁,但看威胁文件位置…

38、Flink 的CDC 格式:canal部署以及示例

Flink 系列文章 一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的…

leetcode1237. 找出给定方程的正整数解

1237. 找出给定方程的正整数解https://leetcode.cn/problems/find-positive-integer-solution-for-a-given-equation/ 难度中等 101 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满…

java生成验证码工具类,java生成图片验证码

java生成验证码工具类,java生成图片验证码 java生成验证码工具类,java生成图片验证码,java生成彩色图片验证码,带干扰线验证码。 调用结果: 工具类调用: GetMapping("/validateCode")public vo…

ubuntu设置右键打开terminator、code

前言: 这里介绍一种直接右键打开本地目录下的terminator和vscode的方法。 一:右键打开terminator 1.安装terminator sudo apt install terminator 2.安装nautilus-actions filemanager-actions sudo apt-get install nautilus-actions filemanager…

【大数据】Flink 中的事件时间处理

Flink 中的事件时间处理 1.时间戳2.水位线3.水位线传播和事件时间4.时间戳分配和水位线生成 在之前的博客中,我们强调了时间语义对于流处理应用的重要性并解释了 处理时间 和 事件时间 的差异。虽然处理时间是基于处理机器的本地时间,相对容易理解&#…

可视化智慧水电站EasyCVR视频智能监控系统方案设计与技术应用介绍

一、背景需求 水电站作为国家重要的能源基地,其安全运行对于保障能源供应和社会稳定具有重要意义。然而,传统的人工监控方式存在着诸多问题,如人力成本高、监控范围有限、反应不及时等。因此,水电站急需引进一种先进的视频智能监…

《Q年文峰》GPT应用的交互式非线性体验

Phoncent博客创始人庄泽峰把自己的小说《Q年文峰》做成GPT应用,显然这是一件值得探索且具有创新意义的事情。 因为传统的阅读体验是线性的,读者只能按照固定的情节顺序进行阅读,而把小说制作成GPT应用后,读者阅读小说的方式是非线…

安卓程序开发——搭建主页框架

一、实验目的 搭建项目框架掌握Android Activity组件使用和Intent机制,加强对Activity生命周期的理解,掌握Fragment的使用。 二、实验设备及器件 Android Studio 三、实验内容 1.创建一个Android应用,设置工程名MobileShop,包…

鸿蒙ArkUI开发-应用添加弹窗

在我们日常使用应用的时候,可能会进行一些敏感的操作,比如删除联系人,这时候我们给应用添加弹窗来提示用户是否需要执行该操作,如下图所示: 弹窗是一种模态窗口,通常用来展示用户当前需要的或用户必须关注的…

智能体AI Agent的极速入门:从ReAct到AutoGPT、QwenAgent、XAgent

前言 如这两天在微博上所说,除了已经在七月官网上线的AIGC模特生成系统外,我正在并行带多个项目组 第二项目组,论文审稿GPT第2版的效果已经超过了GPT4,详见《七月论文审稿GPT第2版:用一万多条paper-review数据集微调…

PBM模型学习(二)Discrete离散方法

1.Discreate离散方法主要涉及Bins的分区、粒径设置、颗粒粒径、Phenomena,如下图所示: ## 2.重要参数设置 Bins分区 Bins表示将颗粒分成了几份 也就是说在PBM模型中,颗粒粒径是离散的,比如实际的颗粒粒径可能是0.001m-0.01m范围内,那么颗粒在这个范围内粒径应该是比较连续…

幻兽帕鲁游戏服务器搭建by阿里云服务器4核16G和32G配置价格表

如何自建幻兽帕鲁服务器?基于阿里云服务器搭建幻兽帕鲁palworld服务器教程来了,一看就懂系列。本文是利用OOS中幻兽帕鲁扩展程序来一键部署幻兽帕鲁服务器,阿里云百科aliyunbaike.com分享官方基于阿里云服务器快速创建幻兽帕鲁服务器教程&…

C++初阶--list

list C的list是标准模板库中的一个容器&#xff0c;用于存储和管理元素的双向链表。提供了一系列访问和修改数据的函数&#xff1b; 使用时需要包含头文件 #include< list > 下面演示下它的一些基础功能 使用list list的遍历 int main() {list<int> lt;lt.push_…

机器学习实验4——CNN卷积神经网络分类Minst数据集

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1; 原理&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;CNN实现分类Minst&#x1f9e1;&#x1f9e1;代码数据预处理&#xff1a;设置基本参数&#xff1a; &#x1f9e…