You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;      
    }

问题原因及解决办法

核心问题

  1. PaintDrawable未设置边界:在Compose的drawBehind中直接调用Drawable的draw方法时,系统不会自动为Drawable分配实际宽高边界,导致ShaderFactory的resize方法无法触发,渐变Shader也就不会被创建,最终Drawable显示为透明。
  2. 新旧环境的隐式差异:原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:39:50