鸿蒙中富文本编辑与展示

富文本在鸿蒙系统如何展示和编辑的?在文章开头我们提出这个疑问,带着疑问来阅读这篇文章。

富文本用途可以展示图文混排的内容,在日常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组件展示分割的内容,本章节就介绍这些东西。后续章节我将依次从简入深,讲解鸿蒙的开发中遇到各种问题。欢迎大家一起交流。如果你在鸿蒙开发中遇到难点,不会的可以私信我,根据我最近的开发经历,已经基本踩完大部分坑,一起交流使我们共同进步。

相关推荐
zhanshuo25 分钟前
在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
harmonyos
zhanshuo27 分钟前
在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo
harmonyos
whysqwhw6 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw7 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw9 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw10 小时前
鸿蒙音频编码
harmonyos
whysqwhw10 小时前
鸿蒙音频解码
harmonyos
whysqwhw10 小时前
鸿蒙视频解码
harmonyos
whysqwhw10 小时前
鸿蒙视频编码
harmonyos
ajassi200010 小时前
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器
华为·开源·harmonyos