Search code examples
androidandroid-jetpack-compose

Change Android Composable pixel colors


I'm trying to change a WebView color for dark mode. For some reason, the steps described in Darken web content in WebView do not produce the wanted result. So I was thinking of inverting the colors of each pixel. Would that be possible during composition?

The following is the code I have:

val activity = LocalActivity.current!!
AndroidView(modifier = Modifier
        .background(colorResource(R.color.white), RoundedCornerShape(10))
        .padding(16.dp),
        factory = {
            WebView(it)
            // The code that seems to have no effect is from here...
                .apply {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                        settings.setAlgorithmicDarkeningAllowed(true)
                    } else if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
                        when (activity.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
                            Configuration.UI_MODE_NIGHT_YES -> {
                                WebSettingsCompat.setForceDark(settings, FORCE_DARK_ON)
                            }

                            Configuration.UI_MODE_NIGHT_NO, Configuration.UI_MODE_NIGHT_UNDEFINED -> {
                                WebSettingsCompat.setForceDark(settings, FORCE_DARK_OFF)
                            }

                            else -> {
                                //
                            }
                        }
                    }
                }
            // ...until here.
        }, update = {
            val reader = activity.resources.openRawResource(R.raw.about).reader()
            val unencodedHtml = reader.readText()
            reader.close()
            val encodedHtml: String =
                Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING)

            it.loadData(encodedHtml, "text/html", "base64")
        })

So would there be any way of changing the Composable's (ie. AndroidView's) pixels during drawing? Like applying a ColorFilter to an ImageBitmap?


Solution

  • You can use obtainGraphicsLayer inside onDrawWithCache or rememberGraphicsLayer() to get GraphicsLayer then apply color filter or blendMode directly to content or drawing of Composable.

    enter image description here

    modifier = Modifier
        .drawWithCache {
            val graphicsLayer = obtainGraphicsLayer()
    
            val values = floatArrayOf(
                -1f, 0f, 0f, 0f, 255f,
                0f, -1f, 0f, 0f, 255f,
                0f, 0f, -1f, 0f, 255f,
                0f, 0f, 0f, 1f, 0f
            )
    
            graphicsLayer.apply {
                record {
                    drawContent()
                }
    //                        blendMode = BlendMode.Difference
                colorFilter = ColorFilter.colorMatrix(ColorMatrix(values))
            }
    
            onDrawWithContent {
                drawLayer(graphicsLayer)
            }
        }
    

    Note: BlendMode.Difference or BlendMode.Exclusion requires api 29 and above but you can apply color filter for any api levels.