Android Layout 視圖綁定(View Binding)

尋找Layout某個View時

之前是使用findViewById找到指定的View

View Binding則是利用Layout名稱來做綁定或者初始化,便可取得指定的View

大多數的情況,可以替代View Binding

但也是有例外

視圖綁定的優點及缺點,可以參考Android官方網站

使用View Binding前的設置

至App build.gradle設置以下內容

android {
    ...
    buildFeatures {
        viewBinding = true
    }
    ...
}
//出現警告Access to 'viewBinding' exceeds its access rights
//改成以下即可,把=拿掉
buildFeatures {
    viewBinding true
}

在Activity中使用

//原先的內容如下
override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_home)
}


//變更為以下方式
//此處的ActivityHomeBinding是activity_home的layout名稱直接轉換
//_後面的英文會自動變大寫,然後刪掉_
private lateinit var binding: ActivityHomeBinding
override fun onCreate(savedInstanceState: Bundle?) {
    binding = ActivityHomeBinding.inflate(layoutInflater)
    setContentView(binding.root)
    //這樣就可以取得直接取到layout裡面的view
    binding.imageview.setBackgroundColor(
        ContextCompat.getColor(
            context,Color.white
        )
}

在Fragment中使用

class TestFragment1: Fragment() {
    private var _binding: FragmentTest1Binding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentTest1Binding.inflate(layoutInflater, container, false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

這裡介紹使用的小細節

1. 在一個Layout裡面include layout,調用方式會不一樣

//需要將此Layout設定id

<include layout="@layout/bottom_check_layout"
android:id="@+id/bottomCheckLayout2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

//使用的時候,一樣先找到此層的binding
//假設@layout/bottom_check_layout裡面有個ImageView id是imageView2

//如下
//binding.bottomCheckLayout2.imageView2就可以這樣使用了

2. ViewStub的使用方法

<androidx.constraintlayout.widget.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <ViewStub
        android:id="@+id/viewstub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/sub_layout"/>
</androidx.constraintlayout.widget.ConstraintLayout>

使用方式會有些不一樣

狀況如下

binding.viewstub.inflate()

這樣Android Studio會顯示錯誤inflate找不到

可以正常編譯、在手機運行

錯誤是因為viewstub轉變成ViewStubProxy

所以找不到inflate()方法

如果把viewstub當作ViewStubProxy用

編譯會錯誤

Unresolved reference: isInflated

Unresolved reference: viewStub

為了解決這個問題,使用方法如下

private lateinit var binding: MainLayoutBinding
private lateinit var bindingSub: SubLayoutBinding
override fun onCreate(savedInstanceState: Bundle?) {
    binding = MainLayoutBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.viewstub.setOnInflateListener { _, inflated ->
        //將設定第二個binding,之後sub_layout裡面的view
        //都將使用bindingSub來呼叫
        bindingSub = SubLayoutBinding.bind(inflated)
    }

    //此處可以透過findViewById來處理,也可以去掉錯誤紅字
    //利用binding.root找到指定的id
    val viewStub = binding.root.findViewById(R.id.viewstub)

    //執行這個後inflate(),上方Listener會觸發
    //就可以找到內部的binding
    viewStub.inflate()
}

訂閱Codeilin的旅程,若有最新消息會通知。

發表留言

透過 WordPress.com 建置的網站.

向上 ↑

使用 WordPress.com 設計專業網站
立即開始使用