【鸿蒙实战开发】HarmonyOS原生能力实现图文混排

208 篇文章 2 订阅
208 篇文章 0 订阅

场景描述

应用中基于原生能力实现图文混排效果有多个方案可实现,推荐使用Flex作父容器实现的方案(方案一),此方案优点在于节点数量少,结构简单。

方案一:基于Flex作父容器实现图文混排

建议基于Flex容器作为父容器实现图文混排,优点在于减少节点数量。

内部头像使用Image组件,中间部分使用Text文本组件,右边使用Text文本组件。
image.png

核心代码
Flex({ direction: FlexDirection.Row }) { 
  Image($r('app.media.heard')) 
    .width(30) 
    .borderRadius(15) 
  Text() { 
    Span('文本') 
      .fontSize(15) 
    ImageSpan($r('app.media.member')) 
      .width('40px') 
      .height('40px') 
      .objectFit(ImageFit.Fill) 
      .verticalAlign(ImageSpanAlignment.BASELINE) 
      .onClick(() => { 
        console.log('测试输出') 
      }) 
    Span('\n') 
    Span('昨天 12:00') 
      .fontSize(12) 
      .fontColor('#ffcac8c8') 
  } 
  .margin({ 
    left: 10 
  }) 

  Text('+关注') 
    .fontSize('28px') 
    .fontColor('#ff8200') 
    .border({ 
      width: 1, 
      color: '#ff8200', 
      radius: 10, 
      style: BorderStyle.Solid 
    }) 
    .padding({ 
      left: 5, 
      right: 5, 
      top: 2, 
      bottom: 2 
    }) 
    .position({ x: 280, y: 2 }) 
}

复制

方案二:基于RelativeContainer相对布局实现图文混排效果

使用此方案RelativeContainer子组件要用alignRules布局组件位置,布局时需指定容器id。参与相对布局的容器内组件必须设置id,不设置id的组件组件不显示,容器id固定为__container__。

如以下核心代码中子组件都设置id,父容器未设置id时,父容器默认id固定为__container__。

image.png

核心代码
// 相对布局 
RelativeContainer() { 
  Image($r('app.media.heard')) 
    .width(30) 
    .borderRadius(15) 
    .id('Image') 
      // 以容器作为锚点布局 
    .alignRules({ 
      top: { anchor: '__container__', align: VerticalAlign.Top }, 
      left: { anchor: '__container__', align: HorizontalAlign.Start } 
    }) 
  Text() { 
    Span('文本') 
      .fontSize(15) 
    ImageSpan($r('app.media.member')) 
      .width('40px') 
      .height('40px') 
      .objectFit(ImageFit.Fill) 
      .verticalAlign(ImageSpanAlignment.BASELINE) 
      .onClick(() => { 
        console.log('测试输出') 
      }) 
    Span('\n') 
    Span('昨天 12:00') 
      .fontSize(12) 
      .fontColor('#ffcac8c8') 
  } 
  .id('Text1') 
  // 以容器内子组件作为锚点进行布局 
  .alignRules({ 
    top: { anchor: 'Image', align: VerticalAlign.Top }, 
    left: { anchor: 'Image', align: HorizontalAlign.End } 
  }) 
  .margin({ 
    left: 10 
  }) 

  Text('+关注') 
    .fontSize('28px') 
    .fontColor('#ff8200') 
    .border({ 
      width: 1, 
      color: '#ff8200', 
      radius: 10, 
      style: BorderStyle.Solid 
    }) 
    .id('Text2') 
      // 以容器内子组件作为锚点进行布局 
    .alignRules({ 
      top: { anchor: 'Text1', align: VerticalAlign.Top }, 
      left: { anchor: 'Text1', align: HorizontalAlign.End }, 
    }) 
    .margin({ 
      left: 150 
    }) 
    .padding({ 
      left: 5, 
      right: 5, 
      top: 2, 
      bottom: 2 
    }) 
}
方案三:基于线性布局实现图文混排效果

基于线性布局实现图文混排时,节点数量会比较多。

image.png

核心代码
Row() { 
  Image($r('app.media.img1')) 
    .width(30) 
    .borderRadius(15) 

  Column() { 
    Row() { 
      Text('文本') 
        .fontSize(15) 
      Image($r('app.media.vvip_1')) 
        .width(30) 
        .borderRadius(15) 
        .margin({ left: 10 }) 
        .position({ x: 40, y: 2 }) 
    } 

    Text('昨天 12:00') 
      .fontSize(12) 
      .fontColor('#ffcac8c8') 
  } 
  .margin({ left: 10, top: 2 }) 
  // 设置Column容器内子组件水平方向上布局 
  .justifyContent(FlexAlign.Start) 
  // 设置Column容器内子组件垂直方向上布局 
  .alignItems(HorizontalAlign.Start) 

  Text('+关注') 
    .fontSize('28px') 
    .fontColor('#ff8200') 
    .border({ 
      width: 1, 
      color: '#ff8200', 
      radius: 10, 
      style: BorderStyle.Solid 
    }) 
    .padding({ 
      left: 5, 
      right: 5, 
      top: 2, 
      bottom: 2 
    }) 
    .position({ x: 280, y: 2 }) 
} 
.width('100%') 
.margin({ left: 10, top: 50 })
方案四:基于StyledString(属性字符串)实现图文混排效果

使用StyledString实现图文混排效果,首先得让Text组件与StyledString绑定,绑定后即可使用StyledString设置文本样式以及对文本进行增、删、改、查等操作。

StyledString是一个方便灵活应用文本样式的对象,Text组件可通过TextController中的setStyleString方法与属性字符串绑定。绑定之后即可通过StyledString对文本进行增、删、改、查等一系列操作,并且可以用StyledString设置文本样式。

注意:

  1. 组件样式和属性字符串样式冲突时,属性字符串优先级高,冲突样式以属性字符串设置样式为准。

  2. Text子组件样式与属性字符串样式冲突,以属性字符串为准。

  3. 属性字符串对象不支持@State修饰。

image.png

核心代码
import { image } from '@kit.ImageKit' 
import { LengthMetrics, LengthMetricsUnit } from '@ohos.arkui.node'; 

@Component 
export struct FourTh { 
  // PixelMap图片 
  imagePixelMap: image.PixelMap | undefined = undefined; 
  // 属性字符串对象 
  mutableStr: MutableStyledString = new MutableStyledString(''); 
  controller: TextController = new TextController(); 
  // 基于属性字符串设置文本样式 
  fontStyle2: StyledStringValue = new TextStyle({ 
    fontColor: '#ffcac8c8', 
    fontSize: LengthMetrics.vp(12) 
  }) 

  async aboutToAppear() { 
    // 获取图片资源并同步解析成PixelMap 
    this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.member')); 
  } 

  // 同步将资源解析成PixelMap 
  private async getPixmapFromMedia(resource: Resource) { 
    let unit8Array = await getContext(this)?.resourceManager?.getMediaContent({ 
      bundleName: resource.bundleName, 
      moduleName: resource.moduleName, 
      id: resource.id 
    }) 
    let imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength)); 
    let createPixelMap: image.PixelMap = await imageSource.createPixelMap({ 
      desiredPixelFormat: image.PixelMapFormat.RGBA_8888 
    }); 
    await imageSource.release(); 
    return createPixelMap; 
  } 

  build() { 
    NavDestination() { 
      Row() { 
        Image($r('app.media.heard')) 
          .width(30) 
          .borderRadius(15) 
          .margin({ 
            right: 10, 
            top: 5 
          }) 
        // Text组件绑定controller 
        Text(undefined, { controller: this.controller }) 
          .fontSize(15) 
        Text('+关注') 
          .fontSize('28px') 
          .fontColor('#ff8200') 
          .border({ 
            width: 1, 
            color: '#ff8200', 
            radius: 10, 
            style: BorderStyle.Solid 
          }) 
          .padding({ 
            left: 5, 
            right: 5, 
            top: 2, 
            bottom: 2 
          }) 
          .position({ x: 280, y: 2 }) 
      } 
      .onAppear(() => { 
        setTimeout(() => { 
          if (this.imagePixelMap !== undefined) { 
            // ImageAttachment: New图形对象并设置样式 
            this.mutableStr = new MutableStyledString(new ImageAttachment({ 
              value: this.imagePixelMap, 
              size: { width: '40px', height: '40px' }, 
              // layoutStyle: { borderRadius: LengthMetrics.vp(10) }, 
              verticalAlign: ImageSpanAlignment.BASELINE, 
              objectFit: ImageFit.Fill 
            })) 
          } 
          // insertString:在指定字符之前插入文本,此处即在图片之前添加文本 
          this.mutableStr.insertString(0, '文本'); 
          // 在图片之后添加文本 
          let str = new StyledString('\n昨天  12:00', [{ 
            start: 0, 
            length: 10, 
            styledKey: StyledStringKey.FONT, 
            styledValue: this.fontStyle2 
          }]) 
          // appendStyledString: 在末尾位置追加新的属性字符串 
          this.mutableStr.appendStyledString(str); 
          // 通过TextController中的setStyledString方法让属性字符串与Text组件绑定 
          this.controller.setStyledString(this.mutableStr); 
        }, 100) 
      }) 
      .height(200) 
      .margin({ left: 10, top: 50 }) 
      .width('100%') 
      .alignItems(VerticalAlign.Top) 
    }.title('方案4') 
  } 
}

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
●更多鸿蒙最新技术知识点,请移步前往小编:https://gitee.com/

在这里插入图片描述

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值