鸿蒙开发实践——基于RichEditor的评论编辑

鸿蒙(HarmonyOS)实战开发篇——基于RichEditor的评论编辑 使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。 阅读详情

RichEditor是支持图文混排和文本交互式编辑的组件,在我们使用的APP中是很常见的,比如评论区编辑内容发布、对话框或者聊天室。下面列举一些遇到的场景需求:场景一:基于文字图片以及@信息的好友评论场景二:右下角的剩余字数场景三:评论中携带所@的用户的附属信息场景四:文本选择区域发生变化或编辑状态下光标位置发生变化回调场景五:自由切换系统键盘和自定义键盘。

方案描述

场景一:基于文字图片以及 @ 信息的好友评论

效果图

方案

1、通过addTextSpan来添加文字,

2、通过addImageSpan来添加图片

3、通过addBuilderSpan来实现一段内容光标不可插入的效果

4、addTextSpan等支持gesture等手势操作,比如onClick点击和onLongPress长按事件

核心代码

1、由于RichEditor是支持图文混排的,所以RichEditor里面的内容也就是由Text和Image组成的,分别通过addTextSpan和addImageSpan添加,而且还可以设置字体和图片样式,如下代码1:

@Entry
@Component
struct getSpans {
  editorController = new RichEditorController()
 
  build() {
    Column() {
      RichEditor({ controller: this.editorController })
        .width('100%')
        .backgroundColor(Color.Yellow)
        .onReady(() => {
          this.editorController.addImageSpan($r("app.media.icon"),
            {
              imageStyle:
              {
                size: ["100px", "100px"]
              }
            })
          this.editorController.addTextSpan('男生女生向前冲',
            {
              style:
              {
                fontColor: Color.Blue,
                fontSize: 30
              }
            })
        })
      Button('getSpans-图片').onClick((event: ClickEvent) => {
        let getSpans = this.editorController.getSpans({ start: 0 })
        console.log('getSpans0' + JSON.stringify(getSpans[0]))
        // 必须进行强转才能获取文字信息或者图片信息
        let span0 = getSpans[0] as RichEditorTextSpanResult
        console.log('图片相关的信息: ' + JSON.stringify(span0))
      })
      Button('getSpans-文字').onClick((event: ClickEvent) => {
        let getSpans = this.editorController.getSpans({ start: 0 })
        console.log('getSpans1' + JSON.stringify(getSpans[1]))
        let span1 = getSpans[1] as RichEditorImageSpanResult
        console.log('文字相关的信息: ' + JSON.stringify(span1))
      })
    }
  }
}

2、在常见的评论区艾特好友时,会将“@华为官方客服”视作一个整体,光标无法插入其中,且第一次按删除键时整体会高亮选中,第二次再按删除键才会删除。需要注意的是,如果使用的全局@Builder,则需要配合bind(this)使用。后续也可以通过事件阻止“即RichEditor控件ClickEvent/TouchEvent支持preventDefault”。

@Entry
@Component
struct BuilderSpan {
  editorController = new RichEditorController()
 
  @Builder
  At(str: string) {
    Stack() {
      Text('@' + str).fontColor(Color.Blue)
    }
  }
 
  build() {
    Column() {
      RichEditor({ controller: this.editorController })
        .width('100%')
        .height(50)
        .backgroundColor(Color.Yellow)
        .onReady(() => {
          this.editorController.addBuilderSpan(() => {
            this.At('华为官方客服')
          })
          this.editorController.addTextSpan('!!!')
        })
    }
  }
}

3、发微博的时候可以输入表情、超链接、文字等一起的内容

代码3:

@Component
struct Index {
  @State message: string = '#超话社区#';
  controller: RichEditorController = new RichEditorController();
  @State show: boolean = false;
 
  build() {
    Column() {
      RichEditor({controller: this.controller})
        .height(56)
        .width("90%")
        .borderStyle(BorderStyle.Solid)
        .borderColor(Color.Black)
        .borderWidth(1)
        .onReady(() => {
        })
      Button('输入表情').onClick((event: ClickEvent) => {
        this.controller.addImageSpan($r('app.media.app_icon'), {
          imageStyle: {
            size: ["80px", "80px"]
          }
        })
      })
      Button('超链接').onClick((event: ClickEvent) => {
        this.controller.addTextSpan(this.message, {
          offset: this.controller.getCaretOffset(),
          style:
          {
            fontColor: Color.Orange,
            fontSize: 16
          },
          gesture:
          {
            onClick: () => {
              console.log('要跳转链接了哦')
            },
            onLongPress: () => {
              console.log('我被长按了')
            }
          }
        })
        this.controller.setCaretOffset(this.controller.getCaretOffset() + this.message.length)
      })
    }
    .width('100%')
  }
}
场景二:右下角的剩余字数

效果图

方案

使用overlay浮层,显示“0/20”字数提示符在组件的右下角。再通过aboutToIMEInput回调(输入法输入内容前),获取插入的文本偏移位置,对输入内容进行限制。

核心代码

import promptAction from '@ohos.promptAction';
 
@Entry
@Component
struct MaxDemo {
  @State message: string = '蜡笔小新';
  controller: RichEditorController = new RichEditorController();
  @State getContentLength: number = 0;
  @State BOnSt:promptAction.ShowToastOptions = {'message': '已超出内容最大限制.'}
 
  build() {
    Column() {
      RichEditor({ controller: this.controller })
        .height(100)
        .borderWidth(1)
        .borderColor(Color.Red)
        .width("100%")
        .overlay(this.getContentLength + "/20", {
          align: Alignment.BottomEnd
        })
        .aboutToIMEInput((value: RichEditorInsertValue) => {
          console.log("insertOffset:" + JSON.stringify(value.insertValue)) //  插入的文本偏移位置。
          if (this.getContentLength < 20) {
            this.getContentLength = this.getContentLength + value.insertValue.length
            console.log('实时的内容长度:' + this.getContentLength)
            return true
          }
          promptAction.showToast(this.BOnSt)
          return false
        })
        .aboutToDelete((value: RichEditorDeleteValue) => {
          console.log('删除:' + JSON.stringify(value))
          this.getContentLength = this.getContentLength - value.length
          return true
        })
    }
    .width('100%')
  }
}

 场景三:评论中携带所 @ 的用户的附属信息

效果图

方案

使用HashMap的set向HashMap中添加或更新一组数据,使用get方法获取指定key所对应的value。

核心代码

@Entry
@Component
struct SameNameDemo {
  controller: RichEditorController = new RichEditorController();
 
  @Builder
  At(str: string) {
    Stack() {
      Text('@' + str).fontColor(Color.Blue)
    }
    .onClick(() => {
      // 添加不同的身份信息
      const hashMap: HashMap<string, number> = new HashMap();
      hashMap.set("friend1", 123);
      let result = hashMap.get("friend1");
      console.log('result: ' + result)
    })
  }
 
  build() {
    Column() {
      RichEditor({ controller: this.controller })
        .height(100)
        .borderWidth(1)
        .borderColor(Color.Red)
        .width("100%")
      Button('好友1').onClick((event: ClickEvent) => {
        this.controller.addBuilderSpan(() => {
          this.At('华为官方客服')
        })
      })
      Button('好友2').onClick((event: ClickEvent) => {
        this.controller.addBuilderSpan(() => {
          this.At('华为官方客服')
        })
      })
    }
    .width('100%')
  }
}

场景四:文本选择区域发生变化或编辑状态下光标位置发生变化回调

效果图

方案

使用RichEditor组件在API 12支持的新接口 onSelectionChange,在文本选择区域发生变化或编辑状态下光标位置发生变化时触发该回调。光标位置发生变化回调时,选择区域的起始位置等于终止位置(即start = end)。

核心代码

@Entry
@Component
struct Index {
  @State message: string = '蜡笔小新';
  controller: RichEditorController = new RichEditorController();
  @State show: boolean = false;
 
  build() {
    Column() {
      RichEditor({controller: this.controller})
        .defaultFocus(true)
        .padding(0)
        .height(56)
        .width("90%")
        .borderStyle(BorderStyle.Solid)
        .borderColor(Color.Black)
        .borderWidth(1)
        .padding({left: 10})
        .onReady(() => {
          this.controller.addTextSpan(this.message, {
            offset: this.controller.getCaretOffset(),
            style:
            {
              fontColor: Color.Orange,
              fontSize: 16
            }
          })
          this.controller.setCaretOffset(this.controller.getCaretOffset() + this.message.length)
        })
        .onSelectionChange((value:RichEditorRange) => {
          console.log('光标位置改变了')
          console.log('start: ' + value.start)
          console.log('end: ' + value.end)
        })
    }
    .width('100%')
  }
}

场景五:自由切换系统键盘和自定义键盘

效果图

方案

使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。

核心代码

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  controller = new RichEditorController()
  @State showKeyboard:boolean = false;
  private listData: (string | number | Resource)[] = [
    $r('app.media.img'), $r('app.media.img_1'), $r('app.media.img_2'), $r('app.media.img_3'), $r('app.media.img_4'), $r('app.media.img_5'), $r('app.media.img_6'),
    $r('app.media.img'), $r('app.media.img_1'), $r('app.media.img_2'), $r('app.media.img_3'), $r('app.media.img_4'), $r('app.media.img_5'), $r('app.media.img_6'),
    $r('app.media.img'), $r('app.media.img_1'), $r('app.media.img_2'), $r('app.media.img_3'), $r('app.media.img_4'), $r('app.media.img_5'), $r('app.media.img_6'),
    $r('app.media.img'), $r('app.media.img_1'), $r('app.media.img_2'), $r('app.media.img_3'), $r('app.media.img_4'), $r('app.media.img_5'), $r('app.media.img_6'),
    $r('app.media.img'), $r('app.media.img_1'), $r('app.media.img_2'), $r('app.media.img_3'), $r('app.media.img_4'), $r('app.media.img_5'), $r('app.media.img_6'),
  ];
 
  // 自定义键盘组件
  @Builder CustomKeyboardBuilder() {
    Column() {
      Text('自定义表情键盘')
        .fontSize(25)
        .fontWeight(900)
      Grid() {
        ForEach(this.listData, (item: string | number | Resource) => {
          GridItem() {
            if (typeof item !== 'number' && typeof item !== 'string') {
              Image(item)
                .width(30).onClick(() => {
                this.controller.addImageSpan(item, { imageStyle: { size: ['110px', '110px'] } })
              })
            }
          }
        })
      }.columnsGap(10).rowsGap(10).padding(5)
      Row() {
        Image($r('app.media.img_7'))
          .width(30)
          .onClick(() => {
            this.controller.deleteSpans({start: this.controller.getCaretOffset() - 1, end: this.controller.getCaretOffset()})
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.End)
      .margin({ bottom: 40 })
    }
    .borderColor(Color.Gray)
    .borderWidth(5)
  }
 
  build() {
    Column() {
      RichEditor({ controller: this.controller })
        .width('100%')
        .borderWidth(1)
        .borderColor(Color.Black)
        .onReady(() => {
          this.controller.addTextSpan('有序排队')
        })
        .customKeyboard(this.showKeyboard ? this.CustomKeyboardBuilder() : undefined)
 
      Button('切换系统键盘与自定义键盘').onClick((event: ClickEvent) => {
        this.showKeyboard = ! this.showKeyboard
      })
    }
    .height('100%')
  }
}
【鸿蒙ArkUI实战开发】基于RichEditor的评论编辑 使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。 阅读详情

相关推荐

HarmonyOS 开发实践 —— 基于RichEditor的评论编辑

使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。

liuhaojiabin的博客 672

鸿蒙开发进阶(HarmonyOS )基于RichEditor的评论编辑

RichEditor是支持图文混排和文本交互式编辑的组件,在使用APP中是很常见的,如评论区编辑内容发布、对话框或者聊天室。下面列举一些具体的场景需求。

adaedwa187545的博客 1356

鸿蒙5.0实战案例:基于RichEditor的评论编辑

RichEditor是支持图文混排和文本交互式编辑的组件,在我们使用的APP中是很常见的,比如评论区编辑内容发布、对话框或者聊天室。下面列举一些遇到的场景需求:场景一:基于文字图片以及@信息的好友评论场景二:右下角的剩余字数场景三:评论中携带所@的用户的附属信息场景四:文本选择区域发生变化或编辑状态下光标位置发生变化回调场景五:自由切换系统键盘和自定义键盘。效果图方案1、通过addTextSpan来添加文字, 2、通过addImageSpan来添加图片 3、通过addBuilderSpan来实现一段内容光标

Maniu_666的博客 1165

HarmonyOS 开发实践——基于RichEditor的评论编辑

使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。

liuhaojiabin的博客 880

【鸿蒙OH实战开发】APP开发之评论回复弹窗开发实践

评论回复模块在图文和视频应用中被广泛使用,包含编辑区域、好友列表、常用表情列表和表情面板(见下图),它允许用户进行输入文字、表情、@好友、选择图片等操作。该模块一般以弹窗的形式展现给用户,通常在图文、视频界面中直接弹出,或者在评论列表上层弹出,本文将从评论列表上层弹出这种相对复杂的场景出发,重点对以下几个方面进行介绍,为开发者提供评论回复弹窗模块开发的最佳实践。弹窗组件的选型以及最终方案的实现软键盘和表情面板切换的适配编辑区域主要细节功能的实现图1效果图模块名称对应图1中序号评论列表1。

2401_88547687的博客 1006

React项目实战:用AntV G6打造可折叠组织架构图(附完整代码)

本文详细介绍了如何在React项目中使用AntV G6库构建一个功能完整的可折叠组织架构图。通过实战代码演示了从环境搭建、自定义节点、折叠状态管理到性能优化的全流程,重点解决了企业级应用中处理复杂树形数据、实现流畅交互等核心问题,并提供了可直接复用的组件代码。

weixin_29016315的博客 312

鸿蒙开发5.0案例分析:基于RichEditor的评论编辑

使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。

2501_91726121的博客 1069

Windows下OpenMBEE项目MMS部署失败经历及改正

在Github里找到了上面的第一份文档,下载了MMS源代码(不知道为什么这个代码跟上面操作克隆得到的MMS代码不一样?好像是因为Gradle的版本问题,我本地之前已经安装过7.6.4的Gradle了,于是我找到gradle-wrapper.properties文件。后面在VScode中运行了一下依然是报这个错误,我在VScode终端直接执行。不知道为什么依然没什么用。打开“Windows PowerShell”。(如果是第一次运行它,将看到更长的输出)导航到要克隆存储库的文件夹,例如,

Yo_lan_da的博客 1868

HarmonyOS 实战开发 —— 基于RichEditor的评论编辑

RichEditor是支持图文混排和文本交互式编辑的组件,在使用APP中是很常见的,如评论区编辑内容发布、对话框或者聊天室。下面列举一些具体的场景需求。

CTrup的博客 1104

QDMA工程搭建/windows驱动编译与性能测试

请注意,根据您的目标操作系统,您可能需要在windows启动配置中启用测试签名的驱动程序,以便启用此驱动程序的安装。右键单击设备,选择更新驱动程序软件,然后选择构建的QDMA驱动程序的文件夹(通常为。创建一个新工程,在IP Catalog中搜索QDMA,双击创建qdma ip核。驱动程序安装安装驱动程序最简单的方法是通过Windows的“设备管理器”。如果系统提示未经验证的驱动程序发布者,请选择无论如何安装此驱动程序软件。本节主要介绍QDMA驱动在Windows系统的源文件、编译和安装过程。

qq_28455081的博客 2286

macOS 12.7.6部署Ollama+Dify避坑指南

本文介绍了在macOS 12.7.6系统下部署Ollama和Dify的详细步骤及避坑指南。主要内容包括:1)关闭系统完整性保护(SIP)以允许修改系统目录;2)安装特定版本的Docker(2.1.0.5)和docker-compose(v2.38.2)以避免兼容性问题;3)配置Ollama服务并下载nomic-embed-text和deepseek-r1:7b模型;4)针对macOS调整Dify的docker配置文件,包括延长超时时间、修改存储路径、增加资源限制等关键设置。文中提供了完整的命令操作步骤和配置

Hi20240217的博客 3100

鸿蒙OH实战开发:基于RichEditor的评论编辑

使用RichEditor的属性customKeyboard控制切换系统键盘还是自定义键盘,添加表情使用addImageSpan,删除内容使用deleteSpans,并通过获取光标所在位置进行删除。

pengjiadashaoye的博客 902

Python+OpenCV实战:雨天车牌识别准确率提升300%的5个关键技巧

本文针对雨天车牌识别准确率骤降的难题,分享了五个基于Python和OpenCV的实战技巧。通过暗通道先验去雾、雨纹抑制、光照不变量颜色空间转换、多尺度自适应阈值分割以及融合传统特征与轻量级深度学习的混合识别策略,系统性地提升了算法在恶劣天气下的鲁棒性。这些方法能有效解决图像模糊、对比度低、字符断裂粘连等问题,为智能交通等实际应用提供可靠解决方案。

k8l9m0n的博客 715

鸿蒙5.0 APP开发案例分析:评论回复弹窗开发实践

评论回复模块在图文和视频应用中被广泛使用,包含编辑区域、好友列表、常用表情列表和表情面板(见下图),它允许用户进行输入文字、表情、@好友、选择图片等操作。该模块一般以弹窗的形式展现给用户,通常在图文、视频界面中直接弹出,或者在评论列表上层弹出,本文将从评论列表上层弹出这种相对复杂的场景出发,重点对以下几个方面进行介绍,为开发者提供评论回复弹窗模块开发的最佳实践。弹窗组件的选型以及最终方案的实现软键盘和表情面板切换的适配编辑区域主要细节功能的实现图1效果图模块名称对应图1中序号评论列表1。

mn_xiaona666的博客 1027

cocos2dx中DrawNode画线锯齿和非凸多边形填充

记录一下在cocos2dx中使用DrawNode所遇到的2个问题 1.画线锯齿问题 ios版本下,在AppController.mm中设置CCEAGLView的multiSampling和numberOfSamples。如下图 CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]

hello-world 5413

python 抖音采集_python爬取抖音视频的实例详解

import requestsimport jsonimport reimport osfrom pprint import pprint as ppimport queueclass DouYin:header = {'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*...

weixin_35795675的博客 1864

鸿蒙开发5.0案例分析:评论回复弹窗开发实践

评论回复模块在图文和视频应用中被广泛使用,包含编辑区域、好友列表、常用表情列表和表情面板(见下图),它允许用户进行输入文字、表情、@好友、选择图片等操作。该模块一般以弹窗的形式展现给用户,通常在图文、视频界面中直接弹出,或者在评论列表上层弹出,本文将从评论列表上层弹出这种相对复杂的场景出发,重点对以下几个方面进行介绍,为开发者提供评论回复弹窗模块开发的最佳实践。弹窗组件的选型以及最终方案的实现软键盘和表情面板切换的适配编辑区域主要细节功能的实现图1效果图模块名称对应图1中序号评论列表1。

2501_91726121的博客 767

bevformer详解(3): 逐行代码讲解

在这篇文章中,我们将从BEVFormer算法代码入手,深入探究BEV转换的流程。BEVFormer是一种基于Transformer的BEV转换模型,其核心思想是利用自注意力机制和交叉注意力机制,从,并通过Object Query与BEV特征的交互,完成3D目标检测和地图分割等任务。https://developer.baidu.com/article/details/3224715bevformer的网络结构由三部分组成, 模型结构所示,其中的是部分,对于的是的结构,对于部分,沿用的中的decoder部分,

@bangbang的博客 3697

鸿蒙开发5.0案例分析:图文混排实战技巧(RichEditor)

本文分享了鸿蒙开发在移动应用领域的多个应用场景及解决方案,主要包括富文本编辑器的图文混排、@用户评论、字数限制等功能实现。文章通过代码示例展示了如何使用RichEditor组件实现文字、图片和特殊内容块(如@信息)的混合排版,以及通过事件回调控制输入内容和字数统计。

2501_91726121的博客 1225

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

oh-topic-editor: OpenHarmony & HarmonyOS平台上基于RichEditor实现的支持添加话题、@用户的文本编辑组件

本文介绍了HarmonyOS NEXT & ArkTS基于RichEditor实现的支持添加话题、@用户的文本编辑组件,阐述了其实现原理并附上了成品链接。

1534

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

上一篇: 鸿蒙开发实践——基于HAR的跨模块C++头文件引用
下一篇: 鸿蒙开发实践——跨语言的复杂参数类型传递
猫猫码代码
博客等级 码龄6年 421粉丝 114原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值