前言

開發 Android 的時候很常使用 Kotlin 方便的語法來取得 view 。 舉例來說我們常常會這樣寫

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val title = textView
        title.text = "I'm a title"
    }
}

最近(好像也不最近了) Google 推出了新的 View Binding 來取代舊有的 Kotlin synthetics 。

如果想要了解更多更詳細的 View Binding 請看這裡

遇到的問題

有時候我們會組合 Android 提供的 View 製作成 Component 組合出一些實用的功能。 想了解更多 Custom View 請看這裡

但因為我們使用了 View Binding 不能透過 Kotlin 直接的取得 Custom View 裡面的 View 。

解決方式

先來看看 Custom View Class 裡我們會怎麼做改寫 假設我們的 custom_view.xml 裡面就只有一個簡單的 titleTextView

class MyCustomView: ConstraintLayout {
    constructor(context: Context) : super(context){ init(context, null) }
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { init(context, attrs) }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ){ init(context, attrs) }

    private lateinit var binding: MyCustomViewBinding
    val title get() = binding.titleTextView // 需要宣告變數,才能讓外部取得

    private fun init(context: Context, attrs: AttributeSet?){
        binding = MyCustomViewBinding.inflate(LayoutInflater.from(context), this)
    }
}

接下來我們會在 activity_main 裡加入這個 custom view

// activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@color/white_five"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.ui.components.MyCustomView
        android:id="@+id/customView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</androidx.constraintlayout.widget.ConstraintLayout>

比較舊方法跟新方式的差距

// 舊的方式

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val title = customView.titleTextView
        title.text = "I'm a title"
    }
}

// 新的方式
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        with(binding.customView){
          title.text = "I'm a title"
          // Custom View Class 需要宣告變數才能夠被存取
        }
    }
}

透過這樣的方式就可以取得 titleTextView 囉。

參考資料

StackOverflow 你我的好朋友