OpenHarmony:RichEditor组件样例开发

news2025/4/15 22:20:48

使用 richEditor 组件实现一个富文本编辑框,包含富文本编辑区域和功能栏,功能栏中有多个按键,可以调整字体大小、字体样式、字体颜色、布局,并可以插入图片。

api 版本:api11

主页面

import { TitleBar } from '../../../../common/TitleBar';
import { Title } from './Title';

@Extend(Column) function cardStyle() {
  .backgroundColor(Color.White)
  .borderRadius(24)
  .width('100%')
  .padding(5)
}

@Entry
@Component
struct RichEditorSample {
  @State setStyle: Boolean = false;
  @State setStyle1: Boolean = false;
  @State setStyle2: Boolean = false;
  @State setStyle3: Boolean = false;
  @State setStyle4: Boolean = false;
  @State setStyle5: Boolean = false;
  @State setStyle6: Boolean = false;
  @State styleDialog: Visibility = Visibility.None;
  @State fontWeightSet: FontWeight = FontWeight.Normal;
  @State fontStyleSet: FontStyle = FontStyle.Normal;
  @State fontDecorationSet: TextDecorationType = TextDecorationType.None;
  @State fontAlignLeftSet: TextAlign = TextAlign.Start;
  @State fontAlignMiddleSet: TextAlign = TextAlign.Center;
  @State fontAlignRightSet: TextAlign = TextAlign.End;
  @State tipsValue: number = 32;
  private start: number = -1;
  private end: number = -1;
  private fontColors: string[] = ["#FA2A2D","#FFBF00","#41BA41","#00AAEE","#3F56EA","#8A2BE2","#000000"];

  controller: RichEditorController = new RichEditorController();

  updateVisible(){
    this.setStyle = !this.setStyle;
    if(this.setStyle){
      this.styleDialog = Visibility.Visible;
    }else{
      this.styleDialog = Visibility.None;
    }
  }

  updateFontWeight(){
    this.setStyle1 = !this.setStyle1;
    if(this.setStyle1){
      this.fontWeightSet = FontWeight.Bolder;
    }else{
      this.fontWeightSet = FontWeight.Normal;
    }
  }

  updateFontStyle(){
    this.setStyle2 = !this.setStyle2;
    if(this.setStyle2){
      this.fontStyleSet = FontStyle.Italic;
    }else{
      this.fontStyleSet = FontStyle.Normal;
    }
  }

  updateFontDecoration(){
    this.setStyle3 = !this.setStyle3;
    if(this.setStyle3){
      this.fontDecorationSet = TextDecorationType.Underline;
    }else{
      this.fontDecorationSet = TextDecorationType.None;
    }
  }

  updateFontAlignLeft(){
    this.setStyle4 = !this.setStyle4;
    if(this.setStyle4){
      this.fontAlignLeftSet = TextAlign.Start;
    }else{
      this.fontAlignLeftSet = TextAlign.JUSTIFY;
    }
  }

  updateFontAlignMiddle(){
    this.setStyle5 = !this.setStyle5;
    if(this.setStyle5){
      this.fontAlignMiddleSet = TextAlign.Center;
    }else{
      this.fontAlignMiddleSet = TextAlign.JUSTIFY;
    }
  }

  updateFontAlignRight(){
    this.setStyle6 = !this.setStyle6;
    if(this.setStyle6){
      this.fontAlignRightSet = TextAlign.End;
    }else{
      this.fontAlignRightSet = TextAlign.JUSTIFY;
    }
  }

  build() {
    Column() {
      TitleBar({ title: $r('app.string.rich_editor_title') })
      Scroll() {
        Column() {
          Title({title:$r('app.string.rich_editor_title')})
            .height("10%")
          RichEditor({ controller: this.controller })
            .onReady(() => {
              this.controller.addTextSpan("Hello World。\n" +
                "Familiar images automatically give people a sense of calm and nostalgia. " +
                "Early web designers liked the elements of the 1980s, but today, the aesthetics of the 1990s.\n",
                {
                  style:
                  {
                    fontColor: Color.Black,
                    fontSize: 16
                  }
                })
              this.controller.addImageSpan($r("app.media.addPhoto"),
                {
                  imageStyle:
                  {
                    size: ["100px", "54px"]
                  }
                })
            })
            .onSelect((value: RichEditorSelection) => {
              this.start = value.selection[0];
              this.end = value.selection[1];
            })
            .height("50%")
            .width("100%")
          Stack() {
            Column() {
              Row({ space: 250 }) {
                Text($r('app.string.rich_editor_style'))
                  .fontSize(14)
                  .padding({top:5})
                Image($r('app.media.ic_close'))
                  .width(25)
                  .height(25)
                  .onClick(() => {
                    this.styleDialog = Visibility.None
                  })
              }.height(25)
              .margin({bottom:10})

              Row({ space: 38 }) {
                Image($r('app.media.ic_B_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontWeight()
                    if(this.end!=this.start){
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          fontWeight: this.fontWeightSet
                        }
                      })
                    }
                  })
                Image($r('app.media.ic_I_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontStyle()
                    if(this.end!=this.start) {
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          fontStyle: this.fontStyleSet
                        }
                      })
                    }
                  })
                Image($r('app.media.ic_U_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontDecoration()
                    if(this.end!=this.start) {
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          decoration: {
                            type: this.fontDecorationSet
                          }
                        }
                      })
                    }
                  })
                Image($r('app.media.ic_left_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontAlignLeft()
                    if(this.end!=this.start) {
                      this.controller.updateParagraphStyle({
                        start: this.start,
                        end: this.end,
                        style:
                        {
                          textAlign:this.fontAlignLeftSet
                        }
                      })
                    }
                  })
                Image($r('app.media.ic_middle_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontAlignMiddle()
                    if(this.end!=this.start) {
                      this.controller.updateParagraphStyle({
                        start: this.start,
                        end: this.end,
                        style:
                        {
                          textAlign:this.fontAlignMiddleSet
                        }
                      })
                    }
                  })
                Image($r('app.media.ic_right_normal'))
                  .width(15)
                  .height(15)
                  .onClick(() => {
                    this.updateFontAlignRight()
                    if(this.end!=this.start) {
                      this.controller.updateParagraphStyle({
                        start: this.start,
                        end: this.end,
                        style:
                        {
                          textAlign:this.fontAlignRightSet
                        }
                      })
                    }
                  })
              }
              .height(25)
              .margin({bottom:10})

              Row({ space: 30 }) {
                ForEach(this.fontColors,(item: string) => {
                  Circle({ width: 15, height: 15 }).fill(item)
                    .onClick(() => {
                      if(this.end!=this.start){
                        this.controller.updateSpanStyle({
                          start: this.start,
                          end: this.end,
                          textStyle:
                          {
                            fontColor: item
                          }
                        })
                      }
                    })
                })
              }.height(25)
              .margin({bottom:10})

              Row({ space: 30 }) {
                Text("Aa")
                  .width(24)
                  .height(24)
                  .fontSize(11)
                  .fontWeight(400)
                  .onClick(() => {
                    this.tipsValue = this.tipsValue - 2
                    if(this.end!=this.start){
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          fontSize: this.tipsValue/2
                        }
                      })
                    }
                  })
                Slider({ style: SliderStyle.InSet, value: this.tipsValue })
                  .width(210)
                  .showTips(true, 'Size:' + this.tipsValue.toFixed())
                  .onChange(value => {
                    this.tipsValue = value
                    if(this.end!=this.start){
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          fontSize: this.tipsValue/2
                        }
                      })
                    }
                  })
                Text("Aa")
                  .width(24)
                  .height(24)
                  .fontSize(17)
                  .fontWeight(400)
                  .onClick(() => {
                    this.tipsValue = this.tipsValue + 2
                    if(this.end!=this.start){
                      this.controller.updateSpanStyle({
                        start: this.start,
                        end: this.end,
                        textStyle:
                        {
                          fontSize: this.tipsValue/2
                        }
                      })
                    }
                  })
              }.height(25).margin({bottom:60})

            }.visibility(this.styleDialog)
            .width("100%")
            .height("85%")
            .margin({bottom:"85%"})
            .zIndex(1)
            .border({
              radius: { topLeft: 15, topRight: 15 },
            })
            .backgroundColor($r('app.color.background_light_gray'))

            Row({ space: 150 }) {
              Image($r('app.media.ic_textstyle_normal'))
                .width(40)
                .height(40)
                .onClick(() => {
                  this.updateVisible()
                })
              Image($r('app.media.ic_picture_normal'))
                .width(35)
                .height(35)
                .onClick(() => {
                  this.controller.addImageSpan($r("app.media.addPhoto"),
                    {
                      imageStyle:
                      {
                        size: ["100px", "54px"]
                      }
                    })
                })
            }
            .padding({top:"50%"})
            .justifyContent(FlexAlign.Center)
            .width("100%")
            .height("15%")
            .zIndex(3)
          }.height("30%")
        }
        .alignItems(HorizontalAlign.Start)
        .cardStyle()
        .constraintSize({ minHeight: '100%' })
      }
      .width('95%')
      .height('80%')
      .backgroundColor($r('app.color.divider_block_color'))
    }.height('100%')
    .width('100%')
    .backgroundColor($r('app.color.divider_block_color'))
    .padding({ left: 20, right: 20 })
  }
}

title 组件


@Component
export struct Title {
  private title!: Resource;

  build() {
    Column() {
      Row() {
        Text(this.title)
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
      }
      .margin({top:"2%",left:"5%"})
      .width('100%')
    }
    .height('100%')
  }
}

更新字体样式

@State setStyle: Boolean = false;
@State fontWeightSet: FontWeight = FontWeight.Normal;
private start: number = -1;
private end: number = -1;
controller: RichEditorController = new RichEditorController();

updateFontWeight(){
  this.setStyle1 = !this.setStyle1;
  if(this.setStyle1){
    this.fontWeightSet = FontWeight.Bolder;
  }else{
    this.fontWeightSet = FontWeight.Normal;
  }
}

Image($r('app.media.ic_B_normal'))
  .width(15)
  .height(15)
  .onClick(() => {  
     this.updateFontWeight()
     if(this.end!=this.start){
       this.controller.updateSpanStyle({
         start: this.start,
         end: this.end,
         textStyle:
         {
            fontWeight: this.fontWeightSet
         }
      })
    }
})

设置一个 boolean 类型变量 setStyle1,设置字体是否加粗,以 setStyle1 的值来控制

点击加粗按钮,setStyle 变为 true,修改 fontWeightSet 的值,再通过 RichEditor 组件控制器的方法 updateSpanStyle 改变选中字段的样式

自定义字体选择滑动条

@State tipsValue: number = 32;

Slider({ style: SliderStyle.InSet, value: this.tipsValue })
  .width(210)
  .showTips(true, 'Size:' + this.tipsValue.toFixed())
  .onChange(value => {
    this.tipsValue = value
    if(this.end!=this.start){
      this.controller.updateSpanStyle({
        start: this.start,
        end: this.end,
        textStyle:
        {
          fontSize: this.tipsValue/2
        }
      })
    }
  })

初始字号为 16,随着 slider 组件的滑动,字号随之变化

总结:

通过 controller.updateSpanStyle 接口修改字体的样式,通过 controller.addImageSpan 来插入图片,使用了 RichEditor、Slider 等组件实现一个富文本编辑功能页面。

注意:

RichEditor 组件框架层未处理拉起输入法时的界面规避,需要应用层处理,代码如下:

import { KeyboardAvoidMode } from '@ohos.arkui.UIContext';

onWindowStageCreate(windowStage){
    windowStage.loadContent('pages/Index', (err, data) => {
     let a = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode();
     windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET);
     if (err) {
        Logger.error(TAG, `Failed to load the content. Cause: ${JSON.stringify(err)}`)
        return
      }
     Logger.info(TAG, `Succeeded in loading the content. Data: ${JSON.stringify(data)}`)
  })
}

在应用 MainAbility/MainAbility.ts 文件中实现

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

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

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

相关文章

iOS - Runloop介绍

文章目录 iOS - Runloop介绍1. 简介1.1 顾名思义1.2. 应用范畴1.3. 如果没有runloop1.4. 如果有了runloop 2. Runloop对象3. Runloop与线程4. 获取Runloop对象4.1 Foundation4.2 Core Foundation4.3 示例 5. Runloop相关的类5.1 Core Foundation中关于RunLoop的5个类5.2 CFRunL…

【机器学习】深度解析KNN算法

深度解析KNN算法 KNN(K-最近邻)算法是机器学习中一种基本且广泛应用的算法,它的实现简单直观,应用范围广泛,从图像识别到推荐系统都有其身影。然而,随着数据量的增长,KNN算法面临着严峻的效率挑…

常见的数学方法

Math类表示数学类,其中的数学方法都被定义成为static形式,所以可以直接通过Math类的类名调用某个数学方法。语法格式: Math.xxx(参数); 例题 输入n个整数a1,a2,a3,......an,求这n个数的最大值max,最小值min&#xff0…

CSS(三)---【盒子模型、边框、外边距合并】

零.前言 本篇主要介绍CSS中最重要的一种概念模型:“盒子模型”。 关于CSS的更多内容,可以查看作者之前的文章: CSS(一)---【CSS简介、导入方式、八种选择器、优先级】-CSDN博客 CSS(二)---【常见属性、复合属性使用】-CSDN博客 一.盒子模…

课时79:流程控制_循环控制_控制解析

1.4.1 控制解析 学习目标 这一节,我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 简介 所谓的流程控制,主要针对的是,当我们处于流程步骤执行的过程中,因为某些特殊的原因,不得不停止既定的操作进行步…

素材投放效果追踪与精准识别:从数据洞察到策略优化的全方位解析

一、数据洞察:深度解析投放效果的核心指标在数字广告的世界里,数据是投放效果的晴雨表。通过深入的数据洞察,广告主可以清晰地掌握广告的实际表现,为后续的策略调整提供有力的支持。曝光量、点击率、转化率和投资回报率等指标&…

MS Edge浏览器坏了?网页播放视频的速度不对

前言 小白是MS Edge浏览器的重度用户。电脑上必须有的两个浏览器:Google Chrome和Microsoft Edge。 前段时间小白在使用MS Edge的时候出了问题:播放视频或者音频的时候总是被莫名其妙加速或者减速,类似于播放视频时候的0.5x或者2.0x。 当时…

Leetcode的正确打开方式

很多新手朋友在学习完数据结构与算法之后,都想找个平台磨练自己的技艺。那么LeetCode绝对是不二之选。但是官网刷题不是很友好,那么今天给大家介绍一款刷LeetCode神器。也是未来工作之后的摸鱼神器。 leetcode-editor 本打工人的摸(nei&am…

OSCP靶场--Zipper

OSCP靶场–Zipper 考点(php zip:// rce[文件上传] CVE-2021-4034提权7z 通配符提权) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.249.229 -sV -sC -Pn --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-29 07:40 EDT …

知识图谱-图数据库-neo4j (1)踩坑记录

1、neo4j 安装 材料 : openjdk11 (neo4j 最低jdk版本要求) neo4j-community-4.4.30 CentOS 7.8 Release Date: 25 January 2024 Neo4j 4.4.30 is a maintenance release with many important improvements and fixes. Neo4j Deployment Center - Graph Database…

使用node爬取视频网站里《龙珠》m3u8视频

1. 找到视频播放网站 百度一下 龙珠视频播放 精挑细选一个可以播放的网站。 如:我在网上随便找了一个播放网站,可以直接在线播放 https://www.xxx.com/play/39999-1-7.html 这里不具体写视频地址了,大家可以自行搜索 2.分析网页DOM结…

【php程序开发从入门到精通】——搭建PHP开发环境

👨‍💻个人主页:开发者-曼亿点 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 曼亿点 原创 👨‍💻 收录于专栏&#xff1a…

大数据学习-2024/3/29-oracle安装

oracle安装 1、检查windows环境是否支持, 企业版和旗舰版。 右键点击属性后查看 2、检查环境中是否存在oracle数据。 此电脑右键点击管理 看开始菜单是否存在Oracle 文件夹。 3、正式安装oracle a、解压我分享的百度网盘数据,(也可以…

目标检测评价标准

主要借鉴:https://github.com/rafaelpadilla/Object-Detection-Metrics?tabreadme-ov-file 主要评价指标、术语: Intersection Over Union (IOU):两个检测框交集面积与并集面积的比值 True Positive (TP):IOU大于阈值的检测框…

车道线检测_Canny算子边缘检测_1

Canny算子边缘检测(原理) Canny算子边缘检测是一种经典的图像处理算法,由John F. Canny于1986年提出,用于精确、可靠地检测数字图像中的边缘特征。该算法设计时考虑了三个关键目标:低错误率(即尽可能多地检…

《QT实用小工具·三》偏3D风格的异型窗体

1、概述 源码放在文章末尾 可以在窗体中点击鼠标左键进行图片切换,项目提供了一些图片素材,整体风格偏向于3D类型,也可以根据需求自己放置不同的图片。 下面是demo演示: 项目部分代码如下所示: 头文件部分&#xff…

基于微信小程序的日语词汇学习设计与实现(论文+源码)_kaic

日语词汇学习小程序 摘 要 日语词汇学习小程序是高校人才培养计划的重要组成部分,是实现人才培养目标、培养学生科研能力与创新思维、检验学生综合素质与实践能力的重要手段与综合性实践教学环节。本学生所在学院多采用半手工管理日语词汇学习小程序的方式&#x…

【c++】类和对象(五)赋值运算符重载

🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好,本篇文章带大家认识赋值运算符重载,const成员,取地址及const取地址操作符重载等内容 目录 1.赋值运算符重载1.1运算符重载1.1.1特性&#…

鸿蒙OS开发实战:【打造自己的搜索入口】

背景 几乎每家应用中都带有搜索功能,关于这个功能的页面不是特别复杂,但如果要追究其背后的一系列逻辑,可能是整个应用中最复杂的一个功能。今天主要实践目标,会抛开复杂的逻辑,尝试纯粹实现一个“搜索主页”&#xf…