Jetpack Compose | 控件篇(二) -- Icon,Image

写在最前

在上一篇,我们学习了Compose 中的 TextTextFieldButton,并在WorkShop中进行了一系列尝试。 除了对他们的效果有了直观的认识外,也感受了Compose的编码乐趣。

本篇我们将继续学习Icon和Image,从命名上我们可以看出他们和 图形、图片 有关,也是 内容呈现 中非常重要的一种载体和方式。

文中代码均基于 1.0.1版本

如无特殊说明,文中的 Compose 均指代 Jetpack compose

文中代码均可在 WorkShop 中获取,本篇代码集中于 post27 包下

Icon

使用方法

翻阅源码,我们可以获知有三个函数用于构建Icon组件。

分别是:

fun Icon(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
)
fun Icon(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
)
fun Icon(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
)

不难发现,仅第一个形参类型不一致,但均是Icon的实际内容。

而其他三个参数,含义分别为:

  • contentDescription: 内容含义描述,用于 无障碍服务 ,如果这个Icon可以被触发,就需要解释它的含义,如果仅仅是装饰性质,可以忽略掉
  • modifier: 修饰器
  • tint: 着色器,可以直接修改Icon实质内容的颜色。从事Android行业的读者并不陌生

而实质内容可以以三种方式进行描述:

  • ImageVector 矢量图
  • ImageBitmap 位图
  • Painter 可被绘制的内容,这是一个抽象的类,类似于Android中的 Drawable

效果

Compose中已经存在一些矢量图资源,例如:

public val Icons.Filled.Favorite: ImageVector
    get() {
        if (_favorite != null) {
            return _favorite!!
        }
        _favorite = materialIcon(name = "Filled.Favorite") {
            materialPath {
                moveTo(12.0f, 21.35f)
                lineToRelative(-1.45f, -1.32f)
                curveTo(5.4f, 15.36f, 2.0f, 12.28f, 2.0f, 8.5f)
                curveTo(2.0f, 5.42f, 4.42f, 3.0f, 7.5f, 3.0f)
                curveToRelative(1.74f, 0.0f, 3.41f, 0.81f, 4.5f, 2.09f)
                curveTo(13.09f, 3.81f, 14.76f, 3.0f, 16.5f, 3.0f)
                curveTo(19.58f, 3.0f, 22.0f, 5.42f, 22.0f, 8.5f)
                curveToRelative(0.0f, 3.78f, -3.4f, 6.86f, -8.55f, 11.54f)
                lineTo(12.0f, 21.35f)
                close()
            }
        }
        return _favorite!!
    }

当然,按照 MaterialDesign, 存在一系列的风格:

  • Filled 默认,图形是内容填充风格
  • Outlined 只有描边,不做填充
  • Rounded 圆形,例如圆形启动图标
  • TwoTone 双调,不确定doc是否写错,和Sharp完全一致,可以看情况搭讪下设计MM,顺带提升下审美
  • Sharp 例如直角图标

均可以在Google Fonts进行定制与体验

Icon(
    Icons.Filled.Call,
    contentDescription = "Call"
)
Icon(
    Icons.Outlined.Call,
    contentDescription = "Call"
)
Icon(
    Icons.Rounded.Call,
    contentDescription = "Call"
)
Icon(
    Icons.TwoTone.Call,
    contentDescription = "Call"
)
Icon(
    Icons.Sharp.Call,
    contentDescription = "Call"
)

选取了部分内置图标进行直观感受。

三种资源使用方式以及Tint:

Icon(
    ImageBitmap.imageResource(id = R.drawable.baseline_fingerprint_black_24dp),
    contentDescription = "Check fingerprint",
    tint = Color.Green
)

icon_demo.webp

Image

使用方式

和Icon的使用类似,同样有三个函数:

fun Image(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)
fun Image(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)
fun Image(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)

和Icon对比,如下参数不同:

  • alignment: 内容对齐方式
  • contentScale: 缩放,类似Android ScaleType
  • alpha: 内容的Alpha通道
  • colorFilter: 色彩过滤器,可以实现tint、滤镜矩阵等,非Compose特有,不再展开

值得一提的是, 图片因其信息量大的特性,实际应用过程中,对于远程资源,总是需要考虑:

  • 加载耗时
  • 清晰度分级
  • 缓存

等内容,本篇我们仅学习静态资源的加载, 而和Compose相关的 资源 加载函数,在Icon中已经有代码示例,本节不再赘述。

结语

又很愉快地学完了一些新知识,当然,在Icon和Image中,依旧存在很多我们没有挖掘的内容,但不用着急,在起始阶段,我们仅需要掌握控件的特性和使用方式。

当我们掌握了UI布局相关的内容后,我们会回过头来,再学习他的原理部分。

打个招呼:其实起始阶段的内容都非常简单,但因为我最近比较懒,而且正在处理一件有挑战的事情,占用了很多精力,所以更新有点拖沓