Jetpack Compose Icon和Image,MaterialLoadingImage以及CoilImage的用法详解

3,497 阅读6分钟

今天我们主要来了解一下Compose的Icon,Image控件,MaterialLoadingImage 以及支持显示网络图片的CoilImage控件。

一:Icon

Icon是显示图标的控件,我们来看看Icon的源码

@Composable
fun Icon(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
) {
    ...
}

@Composable
fun Icon(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
) {
   ...
}

@Composable
fun Icon(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
) {
   ...
}

可以看到Icon主要是有三种构造器,三种分别是第一个参数不一样。一个是imageVector矢量图,一个是bitmap位图,一个是painter。

  • imageVector 矢量图 我们可以通过Icons的方式来添加imageVector
    @Preview()
    @Composable
    fun iconTest(){
      Column() {
          Icon(imageVector = Icons.Filled.Add, contentDescription = "添加")
      }
    }
    
    Jetpack Compose 附带 Icons 对象,给我们提供了很多种类型主题的图标。 共有以下五种不同的图标主题:Filled、Outlined、Rounded、TwoTone 和 Sharp。每个主题包含相同的图标,但视觉风格不同。通常,我们应该选择一种主题,并在整个应用中保持使用这一主题,从而确保一致性。 androidx.compose.material这个包下,会为我们依赖一定量的图标进来供我们直接使用,但如需使用其他任何 Material 图标,请将 material-icons-extended 依赖项添加到 build.gradle 文件。
    dependencies {
    ...
    implementation "androidx.compose.material:material-icons-extended:$compose_version"
    }
    
    但注意material-icons-extended 是一个大型库,可能会影响您的 APK 大小。因此,请考虑在正式 build 中使用 R8/Proguard 来移除未使用的资源。此外,由于大小较大,您的项目的构建时间和 Android Studio 的预览加载时间在开发过程中也可能会增加。
  • bitmap 位图,这个相当于我们以前ImageView去设置bitmap是一个道理
    @Preview()
    @Composable
    fun iconTest(){
      Column() {
          Icon(bitmap = ImageBitmap.imageResource(id = R.drawable.icon_head), contentDescription = "图片Icon")
      }
    }
    
  • painter 通过painterResource去引用资源文件。
    @Preview()
    @Composable
    fun iconTest(){
      Column() {
         Icon(painter = painterResource(id = R.drawable.abc_vector_test), contentDescription = "Icon")
      }
    }
    
  • contentDescription 描述信息
  • modifier 修饰符 详情可查看该篇文章Jetpack Compose Modifier用法详解
  • tint 设置修改图标的颜色。
    @Preview()
    @Composable
    fun iconTest(){
      Column() {
          Icon(painter = painterResource(id = R.drawable.abc_vector_test), contentDescription = "Icon",tint = Color.Yellow,modifier = Modifier.size(20.dp))
          Icon(imageVector = Icons.Filled.Add, contentDescription = "添加",tint = Color.Red,modifier = Modifier.size(20.dp))
          Icon(bitmap = ImageBitmap.imageResource(id = R.drawable.icon_add), contentDescription = "图片Icon",tint = Color.Blue,modifier = Modifier.size(20.dp))
      }
    }
    

二:Image

Image的构造器源码如下

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

我们看到一样会有painter,imageVector,bitmap

  • painter 一样是通过painterResource去设置资源的Id
  • imageVector 也可以通过Icons去设置矢量图
  • bitmap 设置ImageBitmap
  • contentDescription 描述
  • modifier 修饰符 详情可查看该篇文章Jetpack Compose Modifier用法详解
 @Preview()
@Composable
fun imageTest(){
    Column() {
        Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "返回图标",modifier = Modifier.size(20.dp))
        Image(imageVector = Icons.Filled.Add, contentDescription = "添加图标",modifier = Modifier.size(20.dp))
        Image(bitmap = ImageBitmap.imageResource(id = R.drawable.icon_head), contentDescription = "Bitmap",modifier = Modifier.size(20.dp))
    }
}
  • contentScale 类似以前ImageView的scaleType属性。去设置ImageView的显示样式
    • ContentScale.Crop 居中裁剪 类似ScaleType.centerCrop
    • ContentScale.Fit 类似ScaleType.fitCenter
    • ContentScale.FillHeight 充满高
    • ContentScale.FillWidth 充满宽
    • ContentScale.Inside 类似ScaleType.centerInside
    • ContentScale.None 不处理
    • ContentScale.FillBounds 类似ScaleType.fitXY 拉伸撑满宽高
  • alpha 设置透明度
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "返回图标",modifier = Modifier.size(20.dp),contentScale = ContentScale.Crop,alpha = 0.5f)
      }
    }
    
  • colorFilter 用于修改在其安装的[Paint]上绘制的每个像素的颜色的效果。 ColorFilter有三种取值方式。
    • ColorFilter.tint(color: Color, blendMode: BlendMode = BlendMode.SrcIn)第一个参数的意思是用于混合源内容的颜色,第二个参数 将着色颜色合成到时使用的blendMode。 blenModel有28种取值方式。跟我们以前的Xfermode的PorterDuff.Model类似。
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "返回图标",modifier = Modifier.size(20.dp),contentScale = ContentScale.Crop,alpha = 0.5f,colorFilter = ColorFilter.tint(Color.Red,
              BlendMode.SrcIn))
      }
    }
    
    • ColorFilter.colorMatrix(colorMatrix: ColorMatrix) 通过传入一个4x5的矩阵去处理
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "返回图标",modifier = Modifier.size(20.dp),contentScale = ContentScale.Crop,alpha = 0.5f,colorFilter = ColorFilter.colorMatrix( ColorMatrix(floatArrayOf(1f,2f,3f,4f,5f,6f,1f,2f,2f,3f,4f,4f,1f,2f,3f,1f,2f,4f,6f,3f))
      }
    }
    
    • ColorFilter.lighting(multiply: Color, add: Color) 创建可用于模拟简单灯光效果的ColorFilter.照明颜色滤光片由两个参数定义,一个用于将光源相乘颜色和一个用于添加到源颜色
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "返回图标",modifier = Modifier.size(20.dp),contentScale = ContentScale.Crop,alpha = 0.5f,colorFilter = ColorFilter.lighting(Color.Red,
              Color.Blue))
      }
    }
    

三:CoilImage

CoilImage是google推荐我们去使用的加载网络图片的开源库。项目的github地址accompanist。 使用CoilImage需要在app的build.gradle里面导入如下的包:

implementation "com.google.accompanist:accompanist-coil:0.7.1"

CoilImage的构造代码如下:

@Composable
fun CoilImage(
    data: Any,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    colorFilter: ColorFilter? = null,
    fadeIn: Boolean = false,
    requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null,
    imageLoader: ImageLoader = CoilImageDefaults.defaultImageLoader(),
    @DrawableRes previewPlaceholder: Int = 0,
    shouldRefetchOnSizeChange: (currentResult: ImageLoadState, size: IntSize) -> Boolean = DefaultRefetchOnSizeChangeLambda,
    onRequestCompleted: (ImageLoadState) -> Unit = EmptyRequestCompleteLambda,
    error: @Composable (BoxScope.(ImageLoadState.Error) -> Unit)? = null,
    loading: @Composable (BoxScope.() -> Unit)? = null,
) {
    ...
}
  • data 填写网络图片的地址
  • contentDescription 描述
  • modifier 修饰符 详情可查看该篇文章Jetpack Compose Modifier用法详解
  • alignment 对齐方式 Alignment 有如下几种取值
    /**
     * A collection of common [Alignment]s aware of layout direction.
     */
    companion object {
          // 2D Alignments.
          @Stable
          val TopStart: Alignment = BiasAlignment(-1f, -1f)
          @Stable
          val TopCenter: Alignment = BiasAlignment(0f, -1f)
          @Stable
          val TopEnd: Alignment = BiasAlignment(1f, -1f)
          @Stable
          val CenterStart: Alignment = BiasAlignment(-1f, 0f)
          @Stable
          val Center: Alignment = BiasAlignment(0f, 0f)
          @Stable
          val CenterEnd: Alignment = BiasAlignment(1f, 0f)
          @Stable
          val BottomStart: Alignment = BiasAlignment(-1f, 1f)
          @Stable
          val BottomCenter: Alignment = BiasAlignment(0f, 1f)
          @Stable
          val BottomEnd: Alignment = BiasAlignment(1f, 1f)
    
          // 1D Alignment.Verticals.
          @Stable
          val Top: Vertical = BiasAlignment.Vertical(-1f)
          @Stable
          val CenterVertically: Vertical = BiasAlignment.Vertical(0f)
          @Stable
          val Bottom: Vertical = BiasAlignment.Vertical(1f)
    
          // 1D Alignment.Horizontals.
          @Stable
          val Start: Horizontal = BiasAlignment.Horizontal(-1f)
          @Stable
          val CenterHorizontally: Horizontal = BiasAlignment.Horizontal(0f)
          @Stable
          val End: Horizontal = BiasAlignment.Horizontal(1f)
    }
    
  • contentScale 类似以前ImageView的scaleType属性。去设置ImageView的显示样式 上面Image讲过
  • colorFilter 跟上面Image一样
  • fadeIn 设置加载图片渐入的效果
  • imageLoader 图片加载器 默认是CoilImageDefaults.defaultImageLoader
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true
          )
      }
    }
    
  • requestBuilder 设置一些配置,比如请求完图片后转换成圆形的图片,比如缩放等
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true,
              requestBuilder = {
                  transformations(CircleCropTransformation())
              }
          )
      }
    }
    
  • error 请求出错时候显示的控件,比如我们这里给个默认图
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true,
              requestBuilder = {
                  transformations(CircleCropTransformation())
              },
              error = {
                  Image(painter = painterResource(R.drawable.ic_launcher_foreground),contentDescription = "错误时候的图标")
              }
          )
      }
    }
    
  • loading 加载时候显示的控件,比如我们给添加个圆形转圈的loading
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true,
              requestBuilder = {
                  transformations(CircleCropTransformation())
              },
              error = {
                  Image(painter = painterResource(R.drawable.ic_launcher_foreground),contentDescription = "错误时候的图标")
              },
              loading = {
                  Box(Modifier.matchParentSize()) {
                      CircularProgressIndicator(Modifier.align(Alignment.Center))
                  }
              }
          )
      }
    }
    
  • previewPlaceholder 加载前占位的资源Id
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true,
              requestBuilder = {
                  transformations(CircleCropTransformation())
              },
              error = {
                  Image(painter = painterResource(R.drawable.ic_launcher_foreground),contentDescription = "错误时候的图标")
              },
              loading = {
                  Box(Modifier.matchParentSize()) {
                      CircularProgressIndicator(Modifier.align(Alignment.Center))
                  }
              },
              previewPlaceholder=R.drawable.icon_head
          )
      }
    }
    
  • shouldRefetchOnSizeChange 是否应该重新定义尺寸变化 有两个参数一个是ImageState,一个是IntSize。回调里需要设置返回值Boolean类型
  • onRequestCompleted 请求完成后的回调,有个参数是ImageState。ImageState.Success成功,ImageState.Error是失败,ImageLoadState.Loading 加载,ImageLoadState.Empty
    @Preview()
    @Composable
    fun imageTest(){
      Column() {
          CoilImage(
              data = "https://picsum.photos/300/300",
              contentDescription = "My content description",
              modifier = Modifier.size(50.dp),
              fadeIn = true,
              requestBuilder = {
                  transformations(CircleCropTransformation())
              },
              error = {
                  Image(painter = painterResource(R.drawable.ic_launcher_foreground),contentDescription = "错误时候的图标")
              },
              loading = {
                  Box(Modifier.matchParentSize()) {
                      CircularProgressIndicator(Modifier.align(Alignment.Center))
                  }
              },
              previewPlaceholder=R.drawable.icon_head,
              onRequestCompleted = {
                  when(it){
                      is ImageLoadState.Success->{
                          // 成功
                      }
                      is ImageLoadState.Error->{
                          // 失败
                      }
                      is ImageLoadState.Loading->{
                          // 正在请求
                      }
                      is ImageLoadState.Empty->{
                        
                      }
                  }
              }
          )
      }
    }
    

注意使用CoilImage的时候记得添加上网络权限。

<uses-permission android:name="android.permission.INTERNET"/>

四:MaterialLoadingImage

相比于Image,在显示图片的时候可以添加淡入淡出的效果,先来看看MaterialLoadingImage的代码

@Composable
fun MaterialLoadingImage(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    colorFilter: ColorFilter? = null,
    fadeInEnabled: Boolean = true,
    fadeInDurationMs: Int = DefaultTransitionDuration
){
...
}
  • painter 跟Image一致
  • contentDescription 描述
  • modifier 修饰符
  • alignment对齐方式
  • contentScale 设置图片显示的规则,跟Image一致
  • colorFilter 跟Image一致
  • fadeInEnabled 是否渐入渐出
  • fadeInDurationMs 渐入渐出的时间 默认是1000毫秒
@Preview()
@Composable
fun materialLoadingImageTest(){
    MaterialLoadingImage(
        painter = painterResource(id = R.drawable.icon_head),
        contentDescription = "描述",
        modifier = Modifier.size(50.dp),
        contentScale = ContentScale.Crop,
        fadeInEnabled = true,
        fadeInDurationMs = 2000,
//        colorFilter = ColorFilter.lighting(Color.Red, Color.Blue),
        alignment = Alignment.Center
    )
}