Android Compose-Image的使用

640 阅读7分钟

一、Image的介绍:

1、Image的使用

Column(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.Center) {

    val imageModifier = Modifier
        .size(100.dp)
        .border(BorderStroke(1.dp, Black))
        .background(Yellow)
    
    Image(
        painter = painterResource(id = R.mipmap.girl) ,
        contentDescription = "小姐姐",
        modifier = imageModifier
    )
    
    Image(painter = painterResource(id = R.mipmap.ic_marker_yellow), 
        contentDescription = "11" 
    )

}

1dc82f2cc40b9d7d8dc962b6a7bc463.png

2、 Image的属性

public fun Image(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = COMPILED_CODE,
    alignment: Alignment = COMPILED_CODE,
    contentScale: ContentScale = COMPILED_CODE,
    alpha: Float = COMPILED_CODE,
    colorFilter: ColorFilter? = COMPILED_CODE
): Unit
  • painter 需要传入的图片,可以是矢量图,可以是位图 ,常用方法就是painterResource(id = R.mipmap.xxx)

  • contentDescription 图片的描述,如果不是重要的图片展示可以为null

  • modifier用于调整布局算法或绘制装饰内容(例如背景)的修饰符,下文会表述一些image的modifier使用

  • alignment 可选的对齐参数,用于将Painter放置在由宽度和高度定义的给定边界内。默认居中,这个属性比较基础,本文不会过多描述

  • contentScale 可选的缩放参数,用于确定当边界的大小与Painter的固有大小不同时要使用的纵横比缩放,默认均匀缩放图片,并保持宽高比。如果内容小于指定大小,系统会放大图片以适应边界。

  • alpha在屏幕上渲染时可选不透明度,默认情况下,图片将完全不透明

  • colorFilter在屏幕上渲染时应用于Painter的可选colorFilter,可用于更改图片中各个像素的输出。以达到滤镜的效果

二、 contentScale内容缩放:

1、默认(ContentScale.Fit)

均匀缩放图片,并保持宽高比。如果内容小于指定大小,系统会放大图片以适应边界。

代码示例

 Row (
        Modifier.background(White),
        horizontalArrangement = Arrangement.Center ,
        verticalAlignment = Alignment.CenterVertically
            ){
        val imageModifier = Modifier
            .size(150.dp)
            .border(BorderStroke(1.dp, Black))
            .background(Yellow)
        Column {
            Image(
                painter = painterResource(id = R.mipmap.girl) ,
                contentDescription = "小姐姐",
                modifier = imageModifier
            )
        }
        Column(
            Modifier.padding(start =  10.dp)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.girl1) ,
                contentDescription = "小姐姐1",
                modifier = imageModifier
            )
        }
    }

效果如下

53f7070c067b900f925fd091746d3ea.png

这个时候图片等比缩小了,对比一开始的图片我们可以发现图片还是完整展示的

2、将图片居中裁剪到可用空间(ContentScale.Crop)

代码如下

    val imageModifier = Modifier
        .size(150.dp)
        .border(BorderStroke(1.dp, Black))
        .background(Yellow)
    val contentScale = ContentScale.Crop
    Row (
        Modifier.background(White),
        horizontalArrangement = Arrangement.Center ,
        verticalAlignment = Alignment.CenterVertically
            ){
       
        Column {
            Image(
                painter = painterResource(id = R.mipmap.girl) ,
                contentDescription = "小姐姐",
                modifier = imageModifier,
                contentScale = contentScale
            )
        }
        Column(
            Modifier.padding(start =  10.dp)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.girl1) ,
                contentDescription = "小姐姐1",
                modifier = imageModifier,
                contentScale = contentScale
            )
        }
    }

效果如下

d815d73bfa983e9b248f2d8928462f0.png

这里我们可以看见图片将整个背景填充满了,无论横向还是纵向,看起来更饱满但这也导致我们失去了部分展示

3、缩放来源图片,保持宽高比不变,使边界与目标高度匹配。(ContentScale.FillHeight)

因为下面的所有代码示例只替换了 val contentScale 中的值,故后面的属性都只展示和描述效果

效果如下

527dde3e3e360f334099fd33b19683c.png

可以看到为了和高度匹配,横向的图片被裁剪了一部分,而纵向的则不受影响.

4、为 Image 可组合项添加边框
val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.mipmap.avatar),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(100.dp)
        .border(
            BorderStroke(borderWidth, Color.Yellow),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

4eee56aa922a6742830699b2fb9d6f3.png

5、绘制彩虹渐变边框:
val rainbowColorsBrush = remember {
    Brush.sweepGradient(
        listOf(
            Color(0xFF9575CD),
            Color(0xFFBA68C8),
            Color(0xFFE57373),
            Color(0xFFFFB74D),
            Color(0xFFFFF176),
            Color(0xFFAED581),
            Color(0xFF4DD0E1),
            Color(0xFF9575CD)
        )
    )
}
Spacer(modifier = Modifier.width(10.dp))
val borderWidth1 = 4.dp
//为 Image 可组合项添加边框,一种常见的操作是结合使用 Modifier.border() 与 Modifier.clip() 在图片周围创建边框:
Image(
    painter = painterResource(id = R.mipmap.avatar),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(100.dp)
        .border(
            BorderStroke(borderWidth1, rainbowColorsBrush),
            CircleShape
        )
        .padding(borderWidth1)
        .clip(CircleShape)
)

43f39d3aa4fc39b4532b396209d6603.png

三、将 Image 可组合项裁剪为某个形状🔰

这个其实归功于修饰符的属性

Modifier .clip()

这个属性呢,主要是将图片或裁剪成圆形或者圆角的,之前的文章中也提到过将背景裁剪成圆角和圆形的大概使用方法为

Modifier
    .height(167.dp)
    .background(
       colorResource(R.color.color_f5f5f5),
       shape = RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp)
     )

将上例子中的contentScale去掉,并修改imageModifier为如下

val imageModifier = Modifier
        .size(150.dp)
        //加了边框
        .border(BorderStroke(1.dp, Black))
        .background(Yellow)
        .clip( RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp))

正当我自信满满的时候,代码没有生效!尬住了,仔细查看后,原来是因为默认的缩放属性ContentScale.Fit自适应边界导致的,于是我将缩放属性换为ContentScale.Crop,代码生效了,为了体现效果我去掉了图二的contentScale

    val imageModifier = Modifier
        .size(150.dp)
        .border(BorderStroke(1.dp, Black))
        .background(Yellow)
        .clip( RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp))
    val contentScale =ContentScale.Crop
    Row (
        Modifier.background(White),
        horizontalArrangement = Arrangement.Center ,
        verticalAlignment = Alignment.CenterVertically
            ){

        Column {
            Image(
                painter = painterResource(id = R.mipmap.girl) ,
                contentDescription = "小姐姐",
                modifier = imageModifier,
                contentScale = contentScale

            )
        }
        Column(
            Modifier.padding(start =  10.dp)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.girl1) ,
                contentDescription = "小姐姐1",
                modifier = imageModifier,
            )
        }
    }


效果如下

e4fa0d67ffb997fff5fcc212db423b9.png

四、为图片加上彩色边框🪁

    val rainbowColorsBrush = remember {
        Brush.sweepGradient(
            listOf(
                Color(0xFF9575CD),
                Color(0xFFBA68C8),
                Color(0xFFE57373),
                Color(0xFFFFB74D),
                Color(0xFFFFF176),
                Color(0xFFAED581),
                Color(0xFF4DD0E1),
                Color(0xFF9575CD)
            )
        )
    }
    val imageModifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(4.dp, rainbowColorsBrush),
            RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp)
        )
        .background(Yellow)
        .clip( RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp))
    val contentScale =ContentScale.Crop
    Row (
        Modifier.background(White),
        horizontalArrangement = Arrangement.Center ,
        verticalAlignment = Alignment.CenterVertically
            ){

        Column {
            Image(
                painter = painterResource(id = R.mipmap.girl) ,
                contentDescription = "小姐姐",
                modifier = imageModifier,
                contentScale = contentScale

            )
        }
        Column(
            Modifier.padding(start =  10.dp)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.girl1) ,
                contentDescription = "小姐姐1",
                modifier = imageModifier,
            )
        }
    }


效果如下

809987415f14ea9808836da1f5a2032.png

到了这一步,可以看到边框和背景还有图片,是三种不同的体现,可以对比差别

五、自定义图片缩放比例🎉

修改imageModifier 代码如下

 val imageModifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(4.dp, rainbowColorsBrush),
            RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp)
        )
        .background(Yellow)
        .clip( RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp))
        //图片转换为自定义宽高比
        .aspectRatio(16f / 9f)

效果如下

1b824f792e53d2b814a81a10386eeab.png

六、颜色滤镜 - 转换图片的像素颜色👮‍♂️

1、对图片进行色调调节

这一功能主要是通过colorFilter 方法实现,colorFilter 的基本用法,引用官方示例如下

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.tint(Color.Green, blendMode = BlendMode.Darken)
)

可以看到主要是ColorFilter.tint()方法,我们看看它的源码

图片.png

可以看到需要我们传入一个Color颜色,然后传入一个BlendMode(颜色混合的模式【自己的理解】),默认是BlendMode.SrcIn,我们通过官方文档可以看到有如下表格那么多种模式:

混合模式参数效果
BlendMode.Color获取源图像的色调和饱和度,以及目标图像的亮度。
BlendMode.ColorBurn将目标的倒数除以源,然后求结果的倒数。
BlendMode.ColorDodge将目标的倒数除以源。
BlendMode.Darken通过从每个颜色通道中选择最低值来合成源图像和目标图像。
BlendMode.Difference从每个通道的较大值中减去较小值。
BlendMode.Dst删除源图像,仅绘制目标图像。
BlendMode.DstAtop在源图像上合成目标图像,但仅在其与源图像重叠的位置。
BlendMode.DstIn显示目标图像,但仅显示两个图像重叠的位置。
BlendMode.DstOut显示目标图像,但仅在两个图像不重叠的地方显示。
BlendMode.DstOver在目标图像下合成源图像
BlendMode.Exclusion从两幅图像的总和中减去两幅图像乘积的两倍。
BlendMode.Hardlight在调整源图像和目标图像的分量以利于源图像之后,将它们相乘。
BlendMode.Hue获取源图像的色调,以及目标图像的饱和度和亮度。
BlendMode.Lighten通过从每个颜色通道中选择最高值来合成源图像和目标图像。
BlendMode.Luminosity获取源图像的亮度,以及目标图像的色调和饱和度。
BlendMode.Modulate将源图像和目标图像的颜色分量相乘。
BlendMode.Multiply将源图像和目标图像的分量相乘,包括alpha通道。
BlendMode.Overlay在调整源图像和目标图像的分量以有利于目标之后,将它们相乘。
BlendMode.Plus将源图像和目标图像的分量相加。
BlendMode.Saturation获取源图像的饱和度以及目标图像的色调和亮度。
BlendMode.Screen将源图像和目标图像的分量的倒数相乘,并求出结果的倒数。
BlendMode.Softlight对于低于0.5的源值,使用ColorDodge;对于高于0.5的源,使用ColorBurn。
BlendMode.Src删除目标图像,仅绘制源图像。
BlendMode.SrcAtop在目标图像上合成源图像,但仅在其与目标重叠的位置。
BlendMode.SrcIn显示源图像,但仅显示两个图像重叠的位置。
BlendMode.SrcOut显示源图像,但仅在两个图像不重叠的地方显示。
BlendMode.SrcOver在目标图像上合成源图像。
BlendMode.Xor对源图像和目标图像应用逐位异或运算符。

读者可以根据自己的需求选用参数

2、通过颜色矩阵应用图片滤镜

使用如下代码为图片添加黑白滤镜

Image(
    painter = painterResource(id = R.mipmap.avatar),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }),
    modifier = Modifier
        .size(150.dp)
)

效果如下

56150cc1d51b0e515218548bf16e838.png

3、BlendMode.Darken和 Color.Green

 Image(
    painter = painterResource(id = R.mipmap.avatar),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.tint(Color.Green, blendMode = BlendMode.Darken),
    modifier = Modifier
        .size(150.dp)
)

效果如下

5bada51ffe71ad39318dfb03c1c5408.png

4、模糊效果

更改 imageModifier 代码如下

val imageModifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(4.dp, rainbowColorsBrush),
            RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp)
        )
        .background(Yellow)
        .clip( RoundedCornerShape(16.dp, 16.dp, 0.dp, 0.dp))
        .aspectRatio(16f / 9f)
        //模糊效果
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp))
        )

效果如下

d38babbe1e87a159d8887f6031b7971.png

六、加载网络图片👮‍♀️

添加依赖

implementation "io.coil-kt:coil-compose:2.1.0"

使用

@Composable
fun NetworkImage(){
    val url = "https://img-blog.csdnimg.cn/6343e1698dc34686b87dbf50f4eaf0f2.png"
    Column(
        Modifier.padding(top = 50.dp)
    ){
        AsyncImage(
            model = url,
            contentDescription = null
        )



        val modelBuilder = ImageRequest.Builder(LocalContext.current)
            .data(url ?: "")
            .crossfade(false)
            .allowHardware(true)
            .build()

        Image(
            painter = rememberAsyncImagePainter(
                model = modelBuilder
            ),
            contentDescription = "头像",
        )
    }
}

注意:加载https图片的时候,不要抓包;

fe2bfbad9762f5c8b3c59855c6b37ae.png