赞
踩
目录
在使用ViewBinding前要在build.gradle工程模块中加入如下配置:
- android {
- ...
-
- buildFeatures {
- viewBinding = true
- }
-
- ...
- }
在加入上述配置后Android Studio会自动为每一个布局文件都生成一个对应的Binding类。
Binding类的命名规则是将布局文件按驼峰方式重命名后,再加上Binding作为结尾。
例如:
activity_main.xml布局对应的Binding类就是ActivityMainBinding类
fragment_main.xml布局对应的Binding类就是FragmentMainBinding类
假设在activity_main.xml的布局文件中有一个名为ButtonSubmit的Button控件,现在要为这个Button控件设置监听
- class MainActivity : AppCompatActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //setContentView(R.layout.activity_main)
-
- //加载布局,并获取布局中的元素引用
- //LayoutInflater是一个用于从XML布局文件中实例化布局的类。
- //它能够将XML布局文件转换为实际的视图对象
- val binding = ActivityMainBinding.inflate(layoutInflater)
- //通过 binding.root 获取布局的根视图
- setContentView(binding.root)
- //binding.ButtonSubmit使用Button控件
- binding.ButtonSubmit.setOnClickListener{
- //添加点击事件的处理逻辑
- }
- }
- }
如果要在onCreate函数之外使用控件,需要将binding声明成全局变量,如下:
- class MainActivity : AppCompatActivity() {
-
- private lateinit var binding: ActivityMainBinding
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- binding = ActivityMainBinding.inflate(layoutInflater)
- setContentView(binding.root)
- binding.ButtonSubmit.setOnClickListener{
- //添加点击事件的处理逻辑
- }
- }
-
- override fun onDestroy() {
- super.onDestroy()
- binding.ButtonSubmit.setOnClickListener{
- //添加点击事件的处理逻辑
- }
- }
- }
方法一:
- class MainFragment : Fragment() {
- // 使用可空类型定义一个私有的_binding变量,用于存储FragmentMainBinding的实例
- private var _binding: FragmentMainBinding? = null
- // 定义一个绑定的属性访问器,它返回一个非空的FragmentMainBinding实例。
- private val binding get() = _binding!!
- // 使用FragmentMainBinding.inflate方法从给定的LayoutInflater和可选的容器中加载布局。
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- _binding = FragmentMainBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onDestroyView() {
- // 首先调用super.onDestroyView(),以确保Fragment的基类也执行其销毁逻辑
- super.onDestroyView()
- // 将_binding设置为null,释放与视图绑定相关的资源
- _binding = null
- }
-
- }
方法二:
- class MainFragment : Fragment(R.layout.fragment_main) {
-
- private lateinit var binding: FragmentMainBinding
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- // 使用ViewBinding.inflate()方法来加载布局
- binding = FragmentMainBinding.inflate(layoutInflater)
- // 将binding.root添加到Fragment的视图中
- view = binding.root
-
- // 现在可以使用binding对象来访问布局中的元素
- binding.exampleTextView.text = "Hello, ViewBinding!"
- // 为按钮设置点击事件
- binding.exampleButton.setOnClickListener {
- // 按钮点击事件的处理逻辑
- }
- }
- }
这两种方法都是使用ViewBinding在Fragment中绑定布局
1、绑定初始化时机:
第一种方法:在onCreateView中初始化ViewBinding。这是Fragment生命周期中创建视图的阶段,适合在视图创建时立即绑定。
第二种方法:在onViewCreated中初始化ViewBinding。这是Fragment视图创建后,但尚未设置任何额外的视图设置之前,适合在视图创建之后进行绑定。
2、视图返回方式:第一种方法:直接返回binding.root作为onCreateView的结果。这意味着Fragment的根视图是通过ViewBinding生成的。
第二种方法:在onViewCreated中将binding.root赋值给view参数。这通常发生在Fragment的视图已经通过其他方式(例如,直接使用R.layout.fragment_example)创建之后。
3、视图销毁处理:第一种方法:在onDestroyView中将_binding设置为null,以避免内存泄漏。这是因为Fragment可能被重用,所以需要在视图销毁时清理绑定。
第二种方法:通常不需要在onDestroyView中进行特殊处理,因为lateinit的binding会在onDestroyView之前自动清理。
4、类型安全访问:第一种方法:使用_binding!!来强制访问绑定对象,这需要确保_binding在使用前已经被初始化。
第二种方法:使用lateinit var声明binding,这确保了binding在使用前已经被初始化,并且是不可空的。
我们定义fruit_item.xml来作为RecyclerView子项的布局:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="60dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ImageView
- android:id="@+id/fruitImage"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginLeft="20dp"
- android:layout_gravity="center_vertical"
- android:layout_marginTop="10dp"/>
-
- <TextView
- android:id="@+id/fruitName"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginTop="10dp"/>
- </LinearLayout>
-
- </LinearLayout>
编写不用ViewBinding的Adapter来加载和显示这个子项布局:
- package com.example.recyclerviewtest
-
- import android.view.LayoutInflater
- import android.view.View
- import android.view.ViewGroup
- import android.widget.ImageView
- import android.widget.TextView
- import androidx.recyclerview.widget.RecyclerView
- import com.example.myapplicationtestexample.R
-
-
- class FruitAdapter(val fruitList: List<Fruit>) :
- RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
-
- inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
- val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
- val fruitName: TextView = view.findViewById(R.id.fruitName)
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
- return ViewHolder(view)
-
- }
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val fruit = fruitList[position]
- holder.fruitImage.setImageResource(fruit.imageId)
- holder.fruitName.text = fruit.name
- }
-
- override fun getItemCount() = fruitList.size
-
- }
具体细节实现可移步:
RecyclerView的实现http://t.csdnimg.cn/5zWcA
编写使用ViewBinding的Adapter来加载和显示这个子项布局:
- class FruitAdapter(val fruitList: List<Fruit>) : RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
-
- //让ViewHolder的构造函数接收FruitItemBinding这个参数
- //ViewHolder的父类RecyclerView.ViewHolder只会接收View类型的参数
- //因此需要调用binding.root获得fruit_item.xml中根元素的实例传给RecyclerView.ViewHolder
- inner class ViewHolder(binding: FruitItemBinding) : RecyclerView.ViewHolder(binding.root) {
- val fruitImage: ImageView = binding.fruitImage
- val fruitName: TextView = binding.fruitName
- }
- //调用FruitItemBinding的inflate()函数去加载fruit_item.xml布局文件
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding = FruitItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
- return ViewHolder(binding)
- }
-
-
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val fruit = fruitList[position]
- holder.fruitImage.setImageResource(fruit.imageId)
- holder.fruitName.text = fruit.name
- }
-
- override fun getItemCount() = fruitList.size
-
- }
这段代码的核心基本都在onCreateViewHolder()函数和ViewHolder函数当中。
这样就不需要再使用findViewById()函数来查找控件实例了,而是调用binding.fruitImage和binding.fruitName就可以直接引用到相应控件的实例。
假设我们有如下example.xml布局,是希望作为一个通用布局引入到各布局当中的:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <TextView
- android:id="@+id/exampleTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:text="Example"
- android:textSize="20sp" />
-
- </RelativeLayout>
假设需要在 activity_main.xml 布局中引入该布局,我们这样引入:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- ...
- <include
- android:id="@+id/example"
- layout="@layout/example" />
- ...
-
- </LinearLayout>
然后可以直接在MainActivity文件中使用example.xml布局的控件
- class MainActivity : AppCompatActivity() {
-
- private lateinit var binding: ActivityMainBinding
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityMainBinding.inflate(layoutInflater)
- setContentView(binding.root)
-
- binding.example.exampleTextView.text = "Title"
-
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。