作为一个开发人员, 要是不是满足产品经理\ui设计师的各种bt需求. 最近做的产品,需要做一个卡片类型的ui,特别之处在于背景不是长方形的,而是上下边是带有弧度. 首先想到的方案是使用.9的png, 不过考虑到png做横向拉伸后弧度会变形.所以想到第二种方案就是使用svg作为背景, 在绘制背景时动态生成svg,达到适配不同宽度的背景图. 至于能不能实现,还需要做下实验
- 首先,既然作为背景大小需要适配组件的大小, 那么就动态拼装svg字符串 按照个人传统, 还是假设svg是按照360宽度设计的
fun svgBg(color: String = "#ffffff", alpha: Float = 1f) =
fun(width: Int, height: Int): String {
val hIn360 = height * 360 / width
val scale = width * 1f / 360f
return """
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="360" height="${hIn360}"
viewBox="0 0 360 ${hIn360}">
<g transform="matrix(${scale}, 0, 0, ${(scale)}, 0, 0)">
<path
d="M 16 0 s 78.25 -5 164.5 -5 s 164.5 5 164.5 5 a 16 16 0 0 1 16 16 v ${kotlin.math.max(0,hIn360-37)} a 16 16 0 0 1 -16 16 s -78.25 -5 -164.5 -5 s -164.5 5 -164.5 5 a 16 16 0 0 1 -16 -16 V 16 a 16 16 0 0 1 16 -16 Z" transform="translate(0 5)"
style="fill: ${color}; fill-opacity: ${alpha};" />
</g>
</svg>
""".trimIndent()
}
- 其次, 自然就需要有代码来解析这段字符串, 来获取需要绘制到canvas上的数据.通过万能的互联网,找到一个可以解析svg的工具 implementation 'com.caverock:androidsvg-aar:1.4'. 而且这个库可以把svg直接绘制到canvas上或者生成drawable,真是太方便了:).
- 最后, 需要实现Modifier的一个扩展方法, 让svg背景的使用符合compose的习惯
fun Modifier.svgStringBackground(render: (Int, Int) -> String) = composed {
this.drawBehind {
this.drawIntoCanvas {
val svg = SVG.getFromString(render(this.size.width.toInt(), (this.size.height).toInt()))
// create a drawable from svg
val drawable = PictureDrawable(svg.renderToPicture())
drawable?.setBounds(0, 0, this.size.width.toInt(), this.size.height.toInt())
drawable?.draw(it.nativeCanvas)
}
}
}
到这基本就齐活了, 来把这几步组合起来试试看效果吧!
LazyColumn(
state = lazyListState,
modifier =
Modifier.wrapContentWidth()) {
items(100) { index ->
Box(
modifier =
Modifier.fillMaxWidth()
.height(100.dp)
.svgStringBackground(svgBg("#00aaaa", 0.7f))) { Text("item$index content") }
}
}
效果看起来还算凑合, 如下:
最后还有几点不足:
- 在实际应用中,需要调整svg模板的参数, 需要对svg格式有足够的知识
- 到目前为止,所使用的svg库不支持filter标签,所以这种方式,还不能支持阴影等特效.