积分67 / 贡献0

提问0答案被采纳0文章2

[经验分享] RichEditor组件样例开发 原创 精华

深开鸿_董伟 显示全部楼层 发表于 2024-3-22 15:45:40

RichEditor组件样例开发

使用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文件中实现

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

精彩评论1

mean

沙发 发表于 2024-4-7 11:42:47
学习了

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部