Compose中Java渐变Drawable迁移至Kotlin后显示透明问题排查
问题描述
我要把旧Java代码里创建上下渐变Drawable的逻辑迁移到Kotlin+Compose环境,原Java代码能正常生成渐变效果,但迁移后的Kotlin代码中getDrawable()返回的却是透明空Drawable。下面是迁移后的Kotlin代码、Drawable使用方式以及原正常运行的Java代码,请问问题出在哪?
迁移后的Kotlin代码
override fun getDrawable(): Drawable { val sf: ShaderFactory = object : ShaderFactory() { override fun resize(width: Int, height: Int): Shader { return LinearGradient( startX(width), startY(height), endX(width), endY(height), intArrayOf( color1, color2 ), null, Shader.TileMode.MIRROR ) } } val p = PaintDrawable() p.shape = RectShape() p.shaderFactory = sf return p } fun startX(actualWidth: Int): Float { when (type) { Type.SOLID -> return 0f Type.DEGREE_DOWN_UP, Type.DEGREE_UP_DOWN -> return actualWidth / 2.0f Type.DEGREE_LEFT_RIGHT -> return 0.0f Type.DEGREE_RIGHT_LEFT -> return actualWidth.toFloat() else -> {} } return (-1).toFloat() } fun startY(actualHeight: Int): Float { when (type) { Type.SOLID -> return 0f Type.DEGREE_DOWN_UP -> return actualHeight.toFloat() Type.DEGREE_LEFT_RIGHT, Type.DEGREE_RIGHT_LEFT -> return actualHeight / 2.0f Type.DEGREE_UP_DOWN -> return 0f else -> {} } return (-1).toFloat() } fun endX(actualWidth: Int): Float { when (type) { Type.SOLID -> return actualWidth.toFloat() Type.DEGREE_DOWN_UP, Type.DEGREE_UP_DOWN -> return actualWidth / 2.0f Type.DEGREE_LEFT_RIGHT -> return actualWidth.toFloat() Type.DEGREE_RIGHT_LEFT -> return 0f else -> {} } return (-1).toFloat() } fun endY(actualHeight: Int): Float { when (type) { Type.SOLID -> return actualHeight.toFloat() Type.DEGREE_DOWN_UP -> return 0f Type.DEGREE_UP_DOWN -> return actualHeight.toFloat() Type.DEGREE_LEFT_RIGHT, Type.DEGREE_RIGHT_LEFT -> return actualHeight / 2.0f else -> {} } return (-1).toFloat() }
Drawable使用方式(类型为DEGREE_UP_DOWN)
val bg = GradientShading(Shading.Type.DEGREE_UP_DOWN, topColor, bottomColor) LazyColumn( modifier = modifier.fillMaxWidth() .clipToBounds() .drawBehind { drawIntoCanvas { bg.getDrawable().draw(it.nativeCanvas) } }, horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top )
原正常运行的Java代码
@Override public Drawable getDrawable() { ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() { @Override public Shader resize(int width, int height) { LinearGradient lg = new LinearGradient(startX(width), startY(height), endX(width), endY(height), new int[] { color1 , color2 }, null, Shader.TileMode.MIRROR); return lg; } }; PaintDrawable p = new PaintDrawable(); p.setShape(new RectShape()); p.setShaderFactory(sf); return (Drawable)p; } float startX(int actualWidth) { switch (this.type) { case SOLID: return 0; case DEGREE_DOWN_UP: case DEGREE_UP_DOWN: return actualWidth/2.0f; case DEGREE_LEFT_RIGHT: return 0.0f; case DEGREE_RIGHT_LEFT: return actualWidth; } return -1; } float startY(int actualHeight){ switch (this.type) { case SOLID: return 0; case DEGREE_DOWN_UP: return actualHeight; case DEGREE_LEFT_RIGHT: case DEGREE_RIGHT_LEFT: return actualHeight/2.0f; case DEGREE_UP_DOWN: return 0; } return -1; } float endX(int actualWidth){ switch (this.type) { case SOLID: return actualWidth; case DEGREE_DOWN_UP: case DEGREE_UP_DOWN: return actualWidth/2.0f; case DEGREE_LEFT_RIGHT: return actualWidth; case DEGREE_RIGHT_LEFT: return 0; } return -1; } float endY(int actualHeight){ switch (this.type) { case SOLID: return actualHeight; case DEGREE_DOWN_UP: return 0; case DEGREE_UP_DOWN: return actualHeight; case DEGREE_LEFT_RIGHT: case DEGREE_RIGHT_LEFT: return actualHeight/2.0f; } return -1; }
问题原因及解决办法
核心问题
- PaintDrawable未设置边界:在Compose的
drawBehind中直接调用Drawable的draw方法时,系统不会自动为Drawable分配实际宽高边界,导致ShaderFactory的resize方法无法触发,渐变Shader也就不会被创建,最终Drawable显示为透明。 - 新旧环境的隐式差异:原Java代码中,Drawable作为View背景使用时,Android系统会自动为其设置匹配View的边界;但Compose的
drawIntoCanvas没有这个隐式逻辑。
修复方案
方案一:给Drawable手动设置边界
在调用draw前,将Drawable的边界设置为当前绘制区域的大小:
drawBehind { val drawable = bg.getDrawable() // 设置Drawable的边界为当前绘制区域 drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawIntoCanvas { drawable.draw(it.nativeCanvas) } }
方案二:直接使用Compose原生渐变API(更推荐)
既然已经使用Compose,没必要依赖传统Drawable,直接用Compose内置的渐变Brush实现:
LazyColumn( modifier = modifier.fillMaxWidth() .clipToBounds() .background( brush = Brush.verticalGradient( colors = listOf(topColor, bottomColor) ) ), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top )
如果需要保留原有多类型的渐变逻辑,可以封装成自定义Brush工具方法:
fun createGradientBrush(type: Shading.Type, color1: Color, color2: Color): Brush { return when(type) { Shading.Type.DEGREE_UP_DOWN -> Brush.verticalGradient(listOf(color1, color2)) Shading.Type.DEGREE_DOWN_UP -> Brush.verticalGradient(listOf(color2, color1)) Shading.Type.DEGREE_LEFT_RIGHT -> Brush.horizontalGradient(listOf(color1, color2)) Shading.Type.DEGREE_RIGHT_LEFT -> Brush.horizontalGradient(listOf(color2, color1)) Shading.Type.SOLID -> Brush.solidColor(color1) } } // 使用方式 LazyColumn( modifier = modifier.fillMaxWidth() .clipToBounds() .drawBehind { val brush = createGradientBrush(Shading.Type.DEGREE_UP_DOWN, topColor, bottomColor) drawRect(brush = brush) }, // ...其他参数 )
内容的提问来源于stack exchange,提问作者NullPointerException
相关产品推荐
相关产品推荐

