# 4.12:图文混排

ArkUI 开发框架提供了 SpanImageSpan 两个基础组件来实现图文混排的场景,本节笔者简单讲述一下它们的用法。

# 4.12.1:Span组件

Span 组件用来显示一段文本,它只能作为 Text 组件的子组件使用,目前只支持文本的通用属性 (opens new window),比如设置文本的颜色、大小、样式、粗细、字体、行高和装饰线等。

# 4.12.1.1:Span定义介绍

interface SpanInterface {
    (value: string | Resource): SpanAttribute;
}
1
2
3

Span 的构造方法接收一个 string 或者 Resource 类型的参数用来显示一个段文本,简单样例如下所示:

@Component @Entry struct SpanTest {
  build() {
    Column({space: 10}) {
      Text("Hello, OpenHarmony")   // 使用Text来显示文本
      Text() {
        Span("Hello, OpenHarmony") // 使用Span来显示文本
      }
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

样例运行结果如下图所示:

4_12_1_1_1

# 4.12.1.2:Span属性介绍

declare class SpanAttribute extends CommonMethod<SpanAttribute> {
    fontColor(value: ResourceColor): SpanAttribute;
    fontSize(value: number | string | Resource): SpanAttribute;
    fontStyle(value: FontStyle): SpanAttribute;
    fontWeight(value: number | FontWeight | string): SpanAttribute;
    fontFamily(value: string | Resource): SpanAttribute;
    decoration(value: {
        type: TextDecorationType;
        color?: ResourceColor;
    }): SpanAttribute;
    letterSpacing(value: number | string): SpanAttribute;
    textCase(value: TextCase): SpanAttribute;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

Span 支持的属性是 Text 组件支持属性的子集,它的显示效果和 Text 是一样的,笔者不在逐一介绍了,简单样例如下所示:

@Component @Entry struct SpanTest {
  build() {
    Column({space: 10}) {
      Text("Hello, OpenHarmony")          // 使用Text做参照物
      Text() {
        Span("Hello,")                    // 设置字体颜色、大小
          .fontColor(Color.Orange)
          .fontSize(20)
        Span("OpenHarmony")               // 设置字体颜色、大小
          .fontColor(Color.Orange)
          .fontSize(30)
        Span("Hello")                     // 设置字体颜色、大小、样式、字符间距、样式、粗细
          .fontColor(Color.Red)
          .fontSize(20)
          .fontWeight(FontWeight.Bolder)
          .fontStyle(FontStyle.Italic)
          .letterSpacing(3)
        Span("《ArkUI实战》")              // 设置字体大小、装饰线以及字母大写显示
          .decoration({
            type: TextDecorationType.Underline,
            color: Color.Red
          })
          .fontSize(20)
          .textCase(TextCase.UpperCase)
      }
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

样例运行结果如下图所示:

4_12_1_1_2

📢:由上述示例可知:Text 组件可以包含多个 Span 组件按照行排列的形式进行展示,超过一行默认进行换行显示。

# 4.12.1.3:Span属性继承

Span 组件允许从父组件 Text 继承属性,当 Span 未设置属性而父组件 Text 设置了相关属性时,则 Span 默认继承 Text 组件设置的属性,目前支持继承的属性包括:fontColorfontSizefontStylefontWeightdecorationletterSpacingtextCasefontfamily

简单样例如下所示:

@Component @Entry struct SpanTest {
  build() {
    Column({space: 10}) {
      Text() {
        Span("Hello, OpenHarmony") // 默认参照物
      }
      Text() {
        Span("Hello, OpenHarmony") // 继承 Text 属性
      }
      .fontColor(Color.Red)
      .fontSize(20)
      Text() {
        Span("Hello, OpenHarmony") // 继承 Text 属性
        Span("Hello, OpenHarmony") // 覆盖 Text 属性
          .fontColor(Color.Red)
          .fontSize(24)
      }
      .fontColor(Color.Blue)
      .fontSize(20)
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

样例运行结果如下图所示:

4_12_1_3_1

📢:由运行效果可知,当 Span 未设置相关属性而父组件 Text 设置了相关属性时,则 Span 继承父组件的熟悉,若 Span 设置了相关属性则以自身属性为准。

# 4.12.1.4:Span事件介绍

Span 目前只支持点击事件:

export declare class CommonMethod<T> {
  onClick(event: (event?: ClickEvent) => void): T;
}
1
2
3

简单样例如下所示:

import Prompt from '@system.prompt'

@Component @Entry struct SpanTest {
  build() {
    Column({space: 10}) {
      Text("Hello, OpenHarmony")
      Text() {
        Span("Hello,")
          .fontColor(Color.Orange)
          .fontSize(20)
          .onClick((event) => {
            Prompt.showToast({
              message: "Hello"
            })
          })

        Span("OpenHarmony")
          .fontColor(Color.Orange)
          .fontSize(30)
          .onClick((event) => {
            Prompt.showToast({
              message: "OpenHarmony"
            })
          })
        Span("Hello")
          .fontColor(Color.Red)
          .fontSize(20)
          .fontWeight(FontWeight.Bolder)
          .fontStyle(FontStyle.Italic)
          .letterSpacing(3)
          .onClick((event) => {
            Prompt.showToast({
              message: "Hello"
            })
          })
        Span("《ArkUI实战》")
          .decoration({
            type: TextDecorationType.Underline,
            color: Color.Red
          })
          .fontSize(20)
          .textCase(TextCase.UpperCase)
          .onClick((event) => {
            Prompt.showToast({
              message: "《ArkUI实战》"
            })
          })
      }
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
4_12_1_3_1

# 4.12.2:ImageSpan

ImageSpan 组件用来在 Text 文本组件中显示一张图片,它只能作为 Text 组件的子组件使用,目前支持文本的通用属性只有尺寸背景以及边框

# 4.12.2.1:ImageSpan定义介绍

interface ImageSpanInterface {
    (value: ResourceStr | PixelMap): ImageSpanAttribute;
}
1
2
3

ImageSpan 的构造方法接收一个 ResourceStr 或者 PixelMap 类型的参数用来显示一张图片。简单样例如下所示:

@Component @Entry struct test {

  build() {
    Column({space: 10}) {
      Text() {
        ImageSpan($r("app.media.test"))
          .width("100%")
          .height(120)
        ImageSpan("https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/8a/2018new_xin_org.png")
          .width(30)
          .height(30)
        ImageSpan("https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/8a/2018new_xin_org.png")
          .width(30)
          .height(30)
        ImageSpan("https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/8a/2018new_xin_org.png")
          .width(30)
          .height(30)
      }
      .fontSize(20)
      .fontColor(Color.Black)
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

样例运行结果如下图所示:

4_12_2_1_1

📢:当 ResourceStr 是一个网络地址时,需要在配置文件 module.json5 中添加网络权限:

{
  "module": {
    "name": "entry",
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET" // 配置网络权限
      }
    ],
  }
}
1
2
3
4
5
6
7
8
9
10

# 4.12.2.2:ImageSpan属性介绍

declare class ImageSpanAttribute extends CommonMethod<ImageSpanAttribute> {
    verticalAlign(value: ImageSpanAlignment): ImageSpanAttribute;
    objectFit(value: ImageFit): ImageSpanAttribute;
}
1
2
3
4
  • objectFit: 设置图片的缩放类型,和 Image 属性一致,笔者不再多做介绍了。
  • verticalAlign:Text 内部既有 Span 又有 ImageSpan 的场景下,ImageSpan 在竖直方向上的对其方式,目前支持以下几种:
    • TOP: 图片上边沿与文本上边沿对齐。
    • CENTER: 图片中间与文本中间对齐。
    • BOTTOM(默认值): 图片下边沿与文本下边沿对齐。
    • BASELINE: 图片下边沿与文本 BaseLine 对齐。

简单样例如下所示:

@Component @Entry struct test {

  build() {
    Column({space: 10}) {
      Text() {
        ImageSpan($r("app.media.test"))
          .width(50)
          .height(50)
        Span("Hello, OpenHarmony")
      }
      Text() {
        ImageSpan($r("app.media.test"))
          .width(50)
          .height(50)
          .verticalAlign(ImageSpanAlignment.TOP)
        Span("Hello, OpenHarmony")
      }
      Text() {
        ImageSpan($r("app.media.test"))
          .width(50)
          .height(50)
          .verticalAlign(ImageSpanAlignment.CENTER)
        Span("Hello, OpenHarmony")
      }
      Text() {
        ImageSpan($r("app.media.test"))
          .width(50)
          .height(50)
          .verticalAlign(ImageSpanAlignment.BOTTOM)
        Span("Hello, OpenHarmony")
      }
      Text() {
        ImageSpan($r("app.media.test"))
          .width(50)
          .height(50)
          .verticalAlign(ImageSpanAlignment.BASELINE)
        Span("Hello, OpenHarmony")
      }
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

样例运行结果如下图所示:

4_12_2_2_1

# 4.12.2.3:ImageSpan事件介绍

ImageSpan 目前也是只支持点击事件,它和 Span 的用法一致,笔者就不在单独介绍它的用法了。

# 4.12.3:图文混排

图文混排的场景也是很常见的,比如浏览新闻类 APP 的时候经常会有图文混排的场景,在 OpenHarmony 上实现图文混排最简单的方式就是利用 Text 包含 SpanImageSpan 实现,简单样例如下所示:

import Prompt from '@system.prompt'

@Component @Entry struct test {

  build() {
    Column({space: 10}) {
      Text() {
        ImageSpan($r("app.media.app_icon"))
          .size({width: 25, height: 25})
          .verticalAlign(ImageSpanAlignment.CENTER)
          .onClick((event) => {
            Prompt.showToast({
              message: "Hello,《ArkUI实战》"
            })
          })
        Span(" 新的一年已经开启,带上一本 #夜读日历# ")
          .onClick((event) => {
            Prompt.showToast({
              message: "新的一年已经开启,带上一本 #夜读日历# ,继续乘风破浪、跨越山海吧!"
            })
          })
        ImageSpan($r("app.media.love"))
          .size({width: 25, height: 25})
          .verticalAlign(ImageSpanAlignment.CENTER)
          .onClick((event) => {
            Prompt.showToast({
              message: "感谢关注"
            })
          })
        Span(" 继续乘风破浪、跨越山海吧!")
          .onClick((event) => {
            Prompt.showToast({
              message: "新的一年已经开启,带上一本 #夜读日历# ,继续乘风破浪、跨越山海吧!"
            })
          })
        ImageSpan("https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/8a/2018new_xin_org.png")
          .size({width: 25, height: 25})
          .verticalAlign(ImageSpanAlignment.CENTER)
          .onClick((event) => {
            Prompt.showToast({
              message: "感谢关注"
            })
          })
      }
      .fontSize(20)
      .fontColor(Color.Black)
    }
    .padding(10)
    .width("100%")
    .height("100%")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

样例运行结果如下图所示:

4_12_3_1

# 4.12.4:小结

本节笔者简单介绍了使用 SpanImageSpan 实现图文混排功能,目前笔者认为美中不足的是 Text 内部不支持使用 ForEach 循环创建多个 Span 的场景……

请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心