coolchandrakumar

    coolchandrakumar

    2 years ago
    Facing unresolved reference while using TextView/WebView inside composable.
    @Composable
    fun inflateAndroidView() {
        Column(modifier = Modifier.fillMaxWidth().wrapContentSize(), horizontalGravity = Alignment.Start) {
            Text(text = "AndroidView-Compose", modifier = Modifier.padding(all = 16.dp))
    
            AndroidView(view = TextView(ContextAmbient.current).apply {
                text = "InsideTextView Android Widget"
            })
    
            AndroidView(view = WebView(ContextAmbient.current).apply {
                loadData("InsideWebView Android Widget", "text/html", "UTF-8")
            })
        }
    }
    Looking to achieve the same in developement
    pavi2410

    pavi2410

    2 years ago
    Move WebView into a variable and set it to AndroidView
    m

    Mark Murphy

    2 years ago
    what exactly is unresolved? can you be more specific?
    coolchandrakumar

    coolchandrakumar

    2 years ago
    Compile time error for TextView/WebView Unresolved reference error
    Zach Klippenstein (he/him) [MOD]

    Zach Klippenstein (he/him) [MOD]

    2 years ago
    Android views are handled specially by the Compose compiler. When in a
    @Composable
    function, View constructor calls are intercepted and transformed into a function call that has a named parameter for every property of the view. The compiler will look for any
    fun setFoo(foo)
    or
    var foo
    properties in the View class and generate named parameters for each of those. So for
    TextView
    , you could write this:
    TextView(text = "hello")
    . The first time this call is performed in a composition, the view will be created and added to the view hierarchy. On subsequent compositions, the view will not be recreated, but any new values will just be passed to those property setters. This transformation also means that the View’s actual constructor, the one that takes a
    Context
    , is not accessible from inside a
    @Composable
    function. To call the actual constructor, you can either wrap the call in the
    escapeCompose { }
    function (anything inside that lambda will be exempted from the special processing), or pull your view constructor out into a regular, non-Composable function.
    Note that Android Studio is not yet aware of this transformation, so it will complain that the function doesn’t exist, that it’s missing parameters, and that the generated property parameters don’t exist, but the code will actually compile.
    The
    WebComponent
    uses this feature. You can see the call to the generated function on line 83: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:ui/ui-android-view/src/main/java/androidx/ui/androidview/WebComponent.kt;l=83?q=WebComponent&ss=androidx And the extension functions on lines 60 and 64 are what tells the compiler to create those
    ref
    and
    url
    parameters on lines 84 and 85.
    AndroidView
    does the same thing. It’s a composable function that delegates to the
    AndroidViewHolder
    class, and instantiates it by either setting the
    view
    property or the
    resId
    (and callback) properties. https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:ui/ui-core/src/main/java/androidx/ui/viewinterop/ComposedView.kt;l=51?q=%22fun%20AndroidView%22&ss=androidx
    coolchandrakumar

    coolchandrakumar

    2 years ago
    Thanks @Zach Klippenstein (he/him) [MOD] on checking of the answer written following snippet.
    @Composable
    fun inflateAndroidView() {
        Column(modifier = Modifier.fillMaxWidth().wrapContentSize(), horizontalGravity = Alignment.Start) {
            Text(text = "AndroidView-Compose", modifier = Modifier.padding(all = 16.dp))
            TextView(text = "Hello World")
        }
    }
    
    @Composable
    fun TextView(text: String) {
        escapeCompose {
            TextView(ContextAmbient.current).apply {
                setText("$text - InsideTextView")
            }
        }
    }
    it throws run time error
    java.lang.NullPointerException
            at androidx.ui.core.AndroidViewsHandler.onDescendantInvalidated(AndroidViewsHandler.kt:39)
            at android.view.HwApsImpl.isNonEmptyFrameCase(HwApsImpl.java:353)
            at android.view.ViewGroup.invalidateChild(ViewGroup.java:5984)
            at android.view.View.invalidateInternal(View.java:17751)
            at android.view.View.invalidate(View.java:17702)
            at android.view.View.setFrame(View.java:22267)
            at android.widget.TextView.setFrame(TextView.java:7293)
            at android.view.View.layout(View.java:22111)
            at androidx.ui.viewinterop.AndroidViewHolder.onLayout(ComposedView.kt:87)...
    which is at
    layoutNode[child]!!.onInvalidate()
    the same way tried for web view. which is also not working
    pavi2410

    pavi2410

    2 years ago
    I'm using WebView like this
    @Preview(showDecoration = true)
    @Composable
    fun MarkDownParser() {
        val kotlin = """
       # Hello World
         
       **I'm your boss**
       
       ![haha](//hello.com)
       """.trimIndent()
        val ctx = ContextAmbient.current
        val html = parseMd(kotlin)
    
        Column {
            Text(text = html)
            AndroidView(view = webview(ctx, html))
        }
    }
    
    private fun webview(ctx: Context, html: String) =
        WebView(ctx).apply { loadData(html, "text/html", "utf-8") }
    Can you check if the above snippet works for you?
    coolchandrakumar

    coolchandrakumar

    2 years ago
    @pavi2410 Thanks for sharing. With your code, still I’m facing the run time error which is related to
    layoutNode[child]!!.onInvalidate()
    ext.kotlin_version = "1.3.72"
    Here I am attached my gradle file