富文本在鸿蒙系统如何展示和编辑的?在文章开头我们提出这个疑问,带着疑问来阅读这篇文章。
富文本用途可以展示图文混排的内容,在日常App 中非常常见,比如微博的发布与展示,朋友圈的发布与展示,都在使用富文本的编辑与展示。通常我们需要标注不同颜色文本,比如话题,#富文本编辑与展示#,@鸿蒙开发者等,这些都要在编辑时或者发布后展示时标注不同的字体颜色。
一、功能富文本编辑
我们如何实现上边这个富文本编辑器呢,在鸿蒙中通过RichEditor实现,由于官网对RichEditor示例太多,很多开发者找不到自己想要的结果,或者对应的使用实例,下面几个部分,基本满足大部分开发者需求的编写。首先上边有四个主要部分,
1、@某人 的实现;主要包括@某人的添加和删除,通过添加@某人,可以看到添加的时候对颜色进行标红,并设置字体大小。
addAltInfo = (referInfo: ReferInfo) => { this.referInfos.push(referInfo) let tempText = `@${referInfo.mUserName} ` this.richEditorController.addTextSpan( tempText, { style: { fontColor: $r("app.color.v5_theme_color"), fontSize: 15 } } ) }
添加完删除时候我们需要判断是否以@开头,如果已@开头就把Span相关的全部删掉。否则就按照系统本身删除 即可。
if (needValue.startsWith("@")) { // @时候删除全部 for (let index = 0; index < this.referInfos.length; index++) { let referInfo = this.referInfos[index] as ReferInfo let altNickname = `@${referInfo.mUserName} ` if (altNickname == needValue) { this.referInfos.splice(index, 1) this.richEditorController.deleteSpans({ start, end }) deleteFlag = false } } }
2、#话题内容# 的实现与@某人相似,通过#选的话题#,这样来设置添加文本的颜色,字体大小等
addTopic = (topic: string) => { this.richEditorController.addTextSpan( topic, { style: { fontColor: $r("app.color.v5_theme_color"), fontSize: 15 } } ) }
如果在删除时候,我们判断一下span内人字符串是已#开始,我们认为他是输入的话题,这时候我们需要把他的字体颜色改变为普通文本的颜色,这样就可以变成普通文本了。目前我是以#开始计算的,你也可以加上以#开始,并且#结束的时候才改变其颜色。我认为以#开始已经足够了。
if (needValue.startsWith("#")) { this.richEditorController.updateSpanStyle( { start: start, end: end, textStyle: { fontColor: $r("app.color.title"), fontSize: 15 } } ) }
3、自定义表情实现,就是我们App 内自己定义一些相关的表情符号,选择对应的表情,以图片的形式存放在发布微博中。这里FaceID就是我们图片资源。可以设置图片的大小,根据自己需求设置大小。表情的删除因为是ImageSpan所以表情就一块删掉了,不用担心删除一半问题。直接按照系统方法走删除的逻辑就可以了。
addFace = (faceId: Resource) => { this.richEditorController.addImageSpan( faceId, { imageStyle: { size: [16, 16] } } ) this.addDefaultStyle() }
4、基本文本文字输入我们有二种方案,第一种就是每次输入完之后加一个空格,来改变后边字体的颜色的字体大小,这样就不会每次跟着前边的字体大小和颜色了。还有一种就是在每次输入完更新输入的字体颜色,把自己输入改为默认颜色即可。二种目前都不是最优解,但是可以解决临时现在的问题,如果大家有好的办法我们一起交流。目前华为官网也没有很好的例子来实现。
addDefaultStyle(text?: string) { let tempText = " " if (text) { tempText = text } this.richEditorController.addTextSpan( tempText, { style: { fontColor: $r("app.color.title"), fontSize: 15 } } ) }
这种是在每次文本输入的时候改变文本的颜色。
.onDidIMEInput((textRange: TextRange) => { this.richEditorController.updateSpanStyle({ start: textRange.start, end: textRange.end, textStyle: { fontColor: $r("app.color.title"), fontSize: 15 } }) })
5、实时获取文本输入的长度字数,以控制最大输入长度。实现方法就是通过getSpans()或者所有的文本,如果是ImageSpan替换成对应的字符串计算字符。其他的按照文本方式计算。直接累加字符串得到最后的文本。得到文本直接获取他的长度即可。
getInputResult = (): string => { let resultStr: string = "" let resultList = this.richEditorController.getSpans() for (let result of resultList) { if (typeof (result as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { let valueResourceStr = (result as RichEditorImageSpanResult).valueResourceStr if (valueResourceStr) { let index = FaceList.getRealIds().indexOf(valueResourceStr.toString()) let faceStr = FaceList.faceNameStr[index] resultStr += faceStr } } else { let value = (result as RichEditorTextSpanResult).value resultStr += value } } return resultStr }
6、对于输入框编辑器对文本的限制,我们可以通过将要输入内容是否还接收数据来实现,如果已经达到我们要求的最大长度我们可以将onWillChange设置成false来表示不在接收数据即可。
.onWillChange((_changeValue) => { if (this.getInputResult().length >= this.maxLength) { return false } return true })
通过监听onDidChange输入之后数据改变实现输入后数据的变化和输入长度展示。
.onDidChange((_callback) => { this.inputDataChange(this.getInputResult()) })
通过上边几个部分的讲解,我们基本完成的富文本编辑在鸿蒙上边的实现,可以通过上边步骤实现类似微博的发布功能,主要包括文本输入,#话题选择#,@某人,文本删除的功能,基本满足的富文本编辑的需求,如果有不满足的你的需求,可以私信我,我们一起探讨,欢迎你的提起,我们一起进步,共同成长。
二、富文本的展示
富文本的展示指的什么,我们需要展示哪些内容;首先举个例子,文本中链接、#话题#、@鸿蒙开发者、表情图标等这些内容需要再展示时候标注特殊的颜色,点击时候我们需要跳转到对应的界面,在鸿蒙中我们怎么在一串文字文本中,对不同文字设置不同的颜色,并且在点击时候跳转对应的界面呢,展示文字中的图片呢,带着这些问题我们来看下边的内容。
首先鸿蒙提供了文本展示器Text,我们可以通过Text展示,但是如果想特殊标记颜色,我们就需要对文本进行分割了,分割出每段要展示的内容。这里我们以#话题#,链接为例进行分割。这里以通过正则表达式分割之后,以#结束的,我们认为是话题类型,否则认为是长链接。这里的分割内容是把#话题#,长链接分割分割出来。分割出来之后,我们通过字符串把整个文本进行分割成不同内容。最后分割成三种类型,普通文本、话题、长链接类型,然后根据类型,展示对应的问题,如果需要跳转点击文本时候进行跳转。@某人、表情符号分割和这个类似方式,这里不再重复表述。如有疑问请私信提出。
export function splitContent(str: string): LinkTextModel[] { let data = str.match(/(#([^#]+)#)|(https?|rtsp):\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z0-9]{2,}(:[0-9]{1,5})?(\/[\S]*)?|(?<!\S)[a-zA-Z0-9\-]+(\.[a-zA-Z0-9]{2,})+(?!\S|\@)/gi); let result: LinkTextModel[] = []; let start = 0; let tempStr = str data?.forEach((value) => { let tempIndex = tempStr.indexOf(value) result.push({ type: LinkTextEnum.COMMON, content: tempStr.slice(start, tempIndex) }) if (value.startsWith("#")) { result.push({ type: LinkTextEnum.TOPIC, content: value }) } else { result.push({ type: LinkTextEnum.URl, content: value }) } tempStr = tempStr.substring(tempIndex + value.length) }); result.push({ type: LinkTextEnum.COMMON, content: tempStr }) return result; }
分割好的文本是一段一段的,我们需要把这些一段一段的展示出来。如下图所示,根据分割的类型展示不同颜色的问题。这里我们在Text里面用,Span展示文本,设置字体颜色。通过ImageSpan展示图标来展示表情。
Text() { ForEach(this.allTextList, (item: LinkTextModel) => { if (item.type === LinkTextEnum.TOPIC) { ForEach(splitFace(item.content), (item: LinkChildModel) => { if (item.type === LinkTextEnum.Face && item.faceId) { ImageSpan(item.faceId) .width(16) .height(16) } else { Span(item.content) .fontColor("#A34444") .onClick(() => { // 跳转话题详情 }) } }) } else if (item.type === LinkTextEnum.URl) { Span(item.content) .fontColor("#A34444") .onClick(() => { // 跳转Web加载页面,加载web地址 }) } else if (item.type == LinkTextEnum.ALT) { Span(item.content) .fontColor("#A34444") .onClick(() => { // alt 分割跳转个人详情 }) } else { ForEach(splitFace(item.content), (item: LinkChildModel) => { if (item.type === LinkTextEnum.Face && item.faceId) { ImageSpan(item.faceId) .width(16) .height(16) } else { Span(item.content) } }) } }) } .fontSize(14) .fontColor("#333333") .width(CommonConstants.MATCH_PARENT) .margin({ top: 5 }) .padding({ left: 12, right: 12 }) }
阅读本文章,我们已经了解了富文本编辑器的实现,可以按照步骤一步一步实现自己的富文本编辑器,也学会富文本的展示,通过正则表达式分割自己需要的内容,然后通过Text中的span、imagespan组件展示分割的内容,本章节就介绍这些东西。后续章节我将依次从简入深,讲解鸿蒙的开发中遇到各种问题。欢迎大家一起交流。如果你在鸿蒙开发中遇到难点,不会的可以私信我,根据我最近的开发经历,已经基本踩完大部分坑,一起交流使我们共同进步。