Hi there. I have a question - is it possible to change white background of the ComposeUIViewControll...
ł
Hi there. I have a question - is it possible to change white background of the ComposeUIViewController to transparent? We can overlay Swift views over compose even with alpha, but the other way round seems impossible.
ł
Thanks! But I understand that stating "but this line cuts underlying Compose content" means that Compose is below and SwiftUI above. I want to have SwiftUI below Compose.
d
Thanks, I will try to make the color of root view UIViewController as transparent. For now you can make this workaround:
Copy code
ComposeUIViewController {
    // Your Compose code here
}.apply {
    view.backgroundColor = UIColor(white = 0.0, alpha = 0.0)
}
I tried to change
Copy code
rootView.backgroundColor = UIColor(white = 0.5, alpha = 0.5)
Compose library on iOS. But still it draws white background color by default. It is harder to make Compose fully transparent for now. Transparency works only with UIKitView for interoperability.
Sorry, but this feature will have lower priority for now.
j
ł
Thank You guys for checking this. Is this background layer really needed there? I tried to change to other color`view.backgroundColor = UIColor.brownColor` but also does not work. Maybe it is not transparency issue?
Copy code
.apply {
    view.alpha = 0.4
}
this works but it changes the entire view. 
I also tried to use view.layer.compositingFilter = "multiplyBlendMode" to get rid of white pixels but it seems not to work at all
j
If you truly need something, I have a hacky workaround for now. You would need to suppress the
INVISIBLE_MEMBER
&
INVISIBLE_REFERENCE
warnings (see top). This will at least display your composable as a UIViewController with a transparent background. Note: there is still some tweaking necessary regarding input & sizing etc. This is just a first step. Note:
CameraOverlay()
is where your composable should go.
@Dima Avdeev in my understanding supporting this could be beneficial and wouldn’t require major changes. Hopefully my snippet can provide some insights. I think that if
SkiaLayer
supports transparency it might already work out of the box for iOS as shown in
ContextHandler
:
Copy code
protected open val clearColor = if (layer.transparency || hostOs == OS.MacOS) 0 else -1    

fun draw() {
        if (!initContext()) {
            throw RenderException("Cannot init graphic context")
        }
        initCanvas()
        canvas?.apply {
            clear(if (layer.fullscreen && hostOs != OS.MacOS) -1 else clearColor)
            drawContent()
        }
        flush()
}
which is basically my approach (clear canvas and draw content) which seems to be working fine but lacks all the base logic from the
ComposeWindow
UIViewController class. 🙂
thank you color 1
ł
@Jeroen Flietstra Thank You veeeery much! This worked. I don’t mind hacky workarounds… for now 👍
Hello @Jeroen Flietstra @Dima Avdeev I tried to proceed with this hack and subclass ComposeWindow to fix it in a minimal way. I think this should be enough to clear canvas before draw. Unfortunately i get compiler error. Maybe it tells You something. Or maybe You could suggest another approach? 🤔
Copy code
e: Compilation failed: Assertion failed

 * Source files: 
 * Compiler version info: Konan: 1.8.20 / Kotlin: 1.8.20
 * Output kind: FRAMEWORK

e: java.lang.AssertionError: Assertion failed
	at org.jetbrains.kotlin.backend.konan.llvm.KotlinObjCClassInfoGenerator.generateInstanceMethodDescs(KotlinObjCClassInfoGenerator.kt:83)
    ...
Copy code
@file:Suppress(
    "INVISIBLE_MEMBER",
    "INVISIBLE_REFERENCE",
    "FINAL_SUPERTYPE",
    "EXPOSED_SUPER_CLASS",
    "UNRESOLVED_REFERENCE",
    "CANNOT_OVERRIDE_INVISIBLE_MEMBER",
    "NOTHING_TO_OVERRIDE",
    "ABSTRACT_MEMBER_NOT_IMPLEMENTED",
)

package com.example.test

import androidx.compose.runtime.Composable
import org.jetbrains.skiko.GenericSkikoView
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkikoView
import platform.UIKit.UIViewController
import androidx.compose.ui.window.ComposeWindow
import androidx.compose.ui.native.ComposeLayer
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Color
import kotlinx.cinterop.ExportObjCClass


fun MainViewController() =
    TransparentViewController {
        CameraOverlay()
    }

fun TransparentViewController(content: @Composable () -> Unit): UIViewController =
    TransparentComposeWindow().apply {
        this.content = content // wasn't able to use .setContent()
    }

class TransparentComposeWindow : ComposeWindow() {

    override lateinit var content: @Composable () -> Unit
    override fun loadView() {
        super.loadView()
        val cl: ComposeLayer = (this as ComposeWindow).layer as ComposeLayer
        val skiaLayer: SkiaLayer = cl.layer

        val skikoView = GenericSkikoView(skiaLayer, object : SkikoView {
            override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
                canvas.clear(Color.TRANSPARENT)
                cl.scene.render(canvas, nanoTime)
            }
        })

        skiaLayer.skikoView = skikoView // wasn't able to use .addView()
    }
}
j
ClearComposeUIViewController.ios.kt.cpp
ClearComposeLayer.ios.kt
@Łukasz Zieliński I created these modified versions of the existing view controller classes. This seems to be working for me just like the regular ComposeUIViewController, but with a transparent background. I hope this will be a temporary fix and an official fix will be release sometime in the future. I hope this works for you as well without compiler errors.
ł
@Jeroen Flietstra This works! Clickable, auto-resizes and with transparent background. I tried similar approach - to copy the implementations but there were always missing references or complier errors. Seeing your solution now I think too much subclassing messed it up. I’m very grateful to You for this and really impressed how fast You did it. Thanks! 🙏
Updated to compose-mutliplatform v1.5.0. There are only three lines diff vs ComposeUIViewController now required for it to work.
Copy code
canvas.clear(Color.TRANSPARENT)
and
Copy code
backgroundColor = UIColor.clearColor
opaque = false
j
Awesome, thanks!
v
I'm trying to use these files on v1.5.1, but I've run into a wall with compilation errors. This is as far as I've come, but I keep getting these errors and I have no idea what it means.
Copy code
error: Compilation failed: The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ command returned non-zero exit code: 70.
output:
Global is external, but doesn't have external or weak linkage!
%struct.ObjHeader* (%struct.ObjHeader*, %struct.ObjHeader**)* @"kfun:components.TransparentComposeWindow.object-1.<get-focusManager>#internal"
Global is external, but doesn't have external or weak linkage!
%struct.ObjHeader* (%struct.ObjHeader*, %struct.ObjHeader**)* @"kfun:components.TransparentComposeWindow.object-1.<get-layoutDirection>#internal"
Global is external, but doesn't have external or weak linkage!
%struct.ObjHeader* (%struct.ObjHeader*, %struct.ObjHeader**)* @"kfun:components.TransparentComposeWindow.object-1.<get-windowInfo>#internal"
fatal error: error in backend: Broken module found, compilation aborted!

 * Source files: 
 * Compiler version: 1.9.10
 * Output kind: FRAMEWORK
👀 1
ł
I had the same errors when converting to 1.5 - implementing layoutDirection and windowInfo overrides in the anonymous object fixed it.
👆 1
v
Nice! Implementing layoutDirection and windowInfo on the Platform object did the trick. 😃 I took the liberty of creating a Gist with the final files HERE. Feel free to comment with your Github users if you want me to credit you in the Gist. 😃
j
Awesome work for keeping this up to date guys. My gh is @JeroenFlietstra
ł
Thanks @Viktor Nyblom! gh: @cyberhenoch
v
Done! 😃
ł
I tried to upgrade to compose 1.5.10-beta02 but the construction is different now. No TransparentComposeLayer can be set and setting directly canvas.clear(Color.TRANSPARENT) before render results in black background anyway. This is what I’ve come up to till now.
v
Hum.. I don't see any code in that block. Maybe you set the font color to transparent too? 😅
ł
Too much transparency indeed! 😱 File below.
😂 1
v
Nice! You think this line should be uncommented now? (using Kotlin 1.9.0 or something like that)
Copy code
295: // super.viewSafeAreaInsetsDidChange() // TODO: call super after Kotlin 1.8.20
e
With the code from your Gist with Kotlin 1.9.10 and Compose 1.5.1 I also had to set
accessibilityController
in:
Copy code
val platform = object : androidx.compose.ui.platform.Platform by androidx.compose.ui.platform.Platform.Empty {

  override fun accessibilityController(owner: SemanticsOwner) = object : AccessibilityController {
    override fun onSemanticsChange() = Unit
    override fun onLayoutChange(layoutNode: LayoutNode) = Unit
    override suspend fun syncLoop() = Unit
  }

  ...
otherwise I would get the error
Copy code
Uncaught Kotlin exception: kotlin.native.internal.IrLinkageError: Abstract function 'accessibilityController' is not implemented in non-abstract anonymous object
    at 0   KMPTestApp                          0x104b787f3        kfun:kotlin.Throwable#<init>(kotlin.String?){} + 123 
    at 1   KMPTestApp                          0x104b7243b        kfun:kotlin.Error#<init>(kotlin.String?){} + 119 
    at 2   KMPTestApp                          0x104bb358b        kfun:kotlin.native.internal.IrLinkageError#<init>(kotlin.String?){} + 119 
    at 3   KMPTestApp                          0x104bb34ff        kfun:kotlin.native.internal#ThrowIrLinkageError(kotlin.String?){}kotlin.Nothing + 175 
    at 4   KMPTestApp                          0x1053d6587        kfun:TransparentComposeWindow.object-2.accessibilityController#internal + 99 
    at 5   KMPTestApp                          0x10522ac93
👍 2
Anyone got this working for Compose 1.5.11 and Kotlin 1.9.21? @Łukasz Zieliński code with some tweaks for latest changes still gives a black background for me.
ł
nope - the 1.5.0 version is the last one that works for me now
e
@Jeroen Flietstra Any idea how it might work in the new version?
Who do I need to bribe to get Jetbrains to put this on their roadmap 😄
j
I’m not using this anymore but I’d happily take a look see if I can make it work again.
e
Would be much appreciated! I also keep on digging
j
This seems to work for me, please be aware that I just changed things to match types with the recent text field changes (Input types have changed so I had to create a separate SkikoUIKitTextInputService here). This works, it’s still hacky and it’s probably best to take a look at the current implementation in compose-multiplatform-core and see what actual changes need to be implemented here. Good luck with it 🙂
k
@Jeroen Flietstra This fix is working for 1.5.11 👌, I'm thinking of using it in production. I hope no compatibility issues in other iOS version 🤞
🤞 1
i
Starting from
1.6.0-beta02
,
opaque
flag is available out of the box
Copy code
ComposeUIViewController(
    configure = { opaque = false }, // Make compose scene background transparent
    ...
)
thank you color 3
🚀 2
🙏 1
j
That’s great news and greatly appreciated! Thanks a lot! 👌
Awesome to see our effort by the community is used and appreciated as well!
e
Thank you so much! Will definitely check it out!
ł
Really good news! 👍
e
@Ivan Matkov I came around to test this now, the background is now transparent 🚀 but it seems that presses are not passed through to the underlying native UI, is this a known limitation?
i
Please open GH issue with your use case and expected behaviour
656 Views