Unresolved reference for synthetic view when layout is in library module

前端 未结 10 2011
醉梦人生
醉梦人生 2020-12-12 21:37

using Kotlin 1.20.20 (not that it matters, older versions behaves the same)

When layout is in separate library module Android Studio has no problem finding and refer

相关标签:
10条回答
  • 2020-12-12 21:37

    Preconditions

    Do not import the following library import kotlinx.android.synthetic.main.my_view.view.*

    app/MainActivity.kt

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            val view: View = MyView(this)
            view.findViewById<TextView>(R.id.textViewPocLib).text = "I can edit the library components"
            setContentView(view)
    }
    

    my_library/MyView.kt

    class MyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
        LinearLayout(context, attrs, defStyleAttr) {
    
        init {
            LayoutInflater.from(context)
                .inflate(R.layout.my_view, this, true)
        }
    }
    

    GL

    Sources:

    • Bug
    • Building Custom Component
    0 讨论(0)
  • 2020-12-12 21:40

    In an incremental improvement on @pablisco's solution above, in my library I have a file:

    // SyntheticExports.kt
    @file:Suppress("ClassName")
    
    package com.example.library.synthetic.main
    
    import android.view.TextView
    import android.view.View
    import android.view.ViewGroup
    import kotlinx.android.synthetic.main.common_layout.view.rootLayout as syntheticRootLayout
    import kotlinx.android.synthetic.main.common_layout.view.retryButton as syntheticRetryButton
    
    object common_layout {
        object view {
            inline val View.rootLayout: ViewGroup get() = syntheticRootLayout
            inline val View.retryButton: TextView get() = syntheticRetryButton
        }
    }
    

    Then on the other module:

    // MainActivity.kt
    import com.example.library.synthetic.main.common_layout.view.rootLayout
    import com.example.library.synthetic.main.common_layout.view.retryButton
    
    rootView.rootLayout.isVisible = true
    rootView.retryButton.setOnClickListener { doIt() }
    

    If this issue is ever fixed, I just need to change imports to start with "kotlinx.android" instead of "comp.example.library".

    0 讨论(0)
  • 2020-12-12 21:42

    you could try switching to 1.2.30-eap-16 and adding

    androidExtensions {
        experimental = true
    }
    

    to your build.gradle.

    0 讨论(0)
  • 2020-12-12 21:44

    I also got this issue and my solution is:

    • Don't use import kotlinx.android.synthetic.main....*

    • Use findViewById()

    For example I changed from

    textview_id.text = "abc"
    

    to

    findViewById(R.id.textview_id).text = "abc"
    
    0 讨论(0)
  • 2020-12-12 21:52

    As mentioned in the comment by @cesards above this is an on going issue with the Kotlin Android Extentions. And it is not solved as of today.


    Good: Use Custom Views

    My primary suggestion is encapsulating the view and the relevant behavior as a custom view and instead of including it via <include> tag, use it directly in your layout as <com.example.app.YourCustomView>.

    This will work no matter your view class is in another module or not.


    Bad and Ugly: Id Collision Workaround

    However I found a hacky workaround if you only want to get one reference from the included view.

    Follow these steps to use kotlin synthetic imports for the layouts included from other modules:

    1. Give an id to the view you want to get reference of in the included xml file.
    2. Give the same id to the include tag in the including xml file.
    3. Now synthetic import the view (id) from the including layout (not from the included)

    I'm not really sure how and why this works but it's a very fragile and dirty way of reusing layouts.

    Example:

    Your including layout (fragment_example.xml)

    <include
        android:id="@+id/exampleView"
        layout="@layout/example_layout" />
    

    Your included layout (example_layout.xml)

    <merge xmlns:android="http://schemas.android.com/apk/res/android">
    
        <TextView
            android:id="@+id/exampleView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </merge>
    

    Your fragment class (ExampleFragment.kt)

    import kotlinx.android.synthetic.main.fragment_example.exampleView
    
    // Do not import the exampleView through example_layout.exampleView
    
    class ExampleFragment : Fragment() {
        // Do something with imported exampleView
    }
    
    0 讨论(0)
  • 2020-12-12 21:53

    I solved my issue with copy both androidExtension and buildscript from project build.gradle to module that uses the library.

    buildscript {
    
        repositories {
            jcenter()
            google()
        }
        dependencies {
            classpath "com.android.tools.build:gradle:$gradle_version"
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    androidExtensions {
        experimental = true
    }
    

    Note: I use the following version of kotlin and gradle:

    buildscript {
        ext.kotlin_version = '1.3.0'
        ext.gradle_version = '3.0.1'
    
    0 讨论(0)
提交回复
热议问题