ViewBinding与kotlin的绑定机制

ViewBinding

ViewBinding 是一个小型的库,只是DataBinding的一个功能,也就是只有试图,并没有数据这一层
没有数据改变视图也跟着改变,其实就单单为了不在通过findViewByid去根据控件的id拿到布局的每一个个控件,而是会为了每个布局根据它布局的文件名生成一个类,而布局每一个控件id就是这个类的一个个字段,
所以可以获取一个类布局的实例对象,然后根据这个实例获取每一个控件字段,而不再是通过finViewByid去获取每一个控件了
如果项目只需要这个功能,而不需要数据与视图的双向绑定,就只需要用ViewBinding就可以

使用ViewBinding使用DataBinding 一样的,也是在build.gradle 下打开开关。

android{
    viewBinding.enable = true
}

当打开开关后, 就会为所有的布局文件,生成对应的 布局类,利用gradle 技术 自动生成了 命名为 xxxBinding 的类
比如 你新建了一个 R.layout.result_profile 就会自动生成一个叫做 ResultProfileBinding 的类。

R.layout.result_profile

<LinearLayout ... >
        <TextView android:id="@+id/name" />
        <ImageView android:cropToPadding="true" />
        <Button android:id="@+id/button"
            android:background="@drawable/rounded_button" />
    </LinearLayout>

并且这个每个控件的id就是这个ResultProfileBinding 的每一个属性
也就是 有两个属性,一个是名为 name 的 TextView,另一个是名为 button 的 Button。而没有写id的控件就不会生成属性,该布局中的 ImageView 没有 ID,因此绑定类中不存在对它的引用。

所以可以获取一个类布局的实例对象,然后根据这个实例获取每一个控件字段,而不再是通过finViewByid去获取每一个控件了
而想要获取布局类的一个实例对象,就是调用对应布局类的inflate(layoutInflater)

class MainActivity : AppCompatActivity() {

     
    lateinit  var  activityMainBinding :ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //调用对应布局类的Inflate方法
        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        activityMainBinding.name.setOnClickListener { 
            
        }

在上面依旧使用setContextView(R.layout.View)的写法,这里也可换一种写法

每一个布局类还有一个 getRoot() 方法,它获取的根view,也就是布局的顶层view 在这里 这个 ResultProfileBinding 类中的 getRoot() 方法会返回 LinearLayout 这个view

所以我们可以 setContextView 一个根view进去

class MainActivity : AppCompatActivity() {

    lateinit  var  activityMainBinding :ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
      //先获取类布局实例对象
        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        //再设置实例对象的根view进去
        setContentView( activityMainBinding.root)
       //使用类布局实例对象的每一个控件属性
        activityMainBinding.name.setOnClickListener {

        }

那对应fragment也是一样的

class Fragment : Fragment() {

    lateinit  var  activityMainBinding : ActivityMainBinding 
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
        val view = activityMainBinding.root
        return view
    }
}

这里因为DataBinding跟ViewBinding 在这里的功能是一致的,所以我们也一起把这一块的说下

上面写通过调用对应布局类的inflate方法获取类实例对象,然后再调用setContextView(布局类对象实例的根view)

在Databinding的话它依旧可以这么做,不过它还有其他一种写法, 可以直接操作
就是调用 DataBindingUtil.setContentView()。这个方法就是把上面两部操作一起做了,
即设置了setContentview,又获取到了一个类实例对象

class MainActivity : AppCompatActivity() {

    lateinit  var  activityMainBinding :ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        activityMainBinding.name.setOnClickListener {

        }

DataBindingUtil.inflate 也是可以 获取一个布局类实例
但是他跟上面的对应布局类.inflate 也就是 跟 ActivityMainBinding.inflate 不同
在上面的 ActivityMainBinding.inflate 中,因为已经确认了类似就是 ActivityMainBinding
所以在定义变量不需要申明类型,在 inflate后不需要申明类型,
但是你用 DataBindingUtil.inflate ,那就得二选一 申明一次该类的类型

在acitivity中:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        //两种写法,第一种是在变量申明
        val activityMainBinding :ActivityMainBinding=
            DataBindingUtil.inflate(layoutInflater, R.layout.activity_main, null, false)
        
        
        //第二种是在 inflate<>加
        val activityMainBinding =
            DataBindingUtil.inflate<ActivityMainBinding>(layoutInflater, R.layout.activity_main, null, false)
        
        setContentView(activityMainBinding.root)

在fragment中

class MainFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

         //两种写法,第一种是在变量申明
        val fragmentMainBinding: FragmentMainBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
        //第二种是在 inflate<>加
        val fragmentMainBinding = DataBindingUtil.inflate<FragmentMainBinding>(inflater,R.layout.fragment_main, container, false)
        return fragmentMainBinding.root
    }
}

如果说当前情况是已经能获取view实例了,比如说通过 LayoutInflater 获取view实例了,那么也可以通过

DataBindingUtil.bind 或者 MyLayoutBinding.bind()去获取这个view对应的布局类实例

val view = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent)
val binding: ViewDataBinding? = DataBindingUtil.bind(view)
val binding: ViewDataBinding? = MyLayoutBinding.bind(view)

kotlin的绑定机制

kotlin的绑定机制 也是能够让我们不再需要findViewById去获取布局下的一个个控件实例。

想要使用 kotlin的绑定机制 需要配置如下
也是再module的build.gradle 写上

plugins {
    id 'kotlin-android-extensions'//启用绑定机制
}

启用绑定机制后,可以直接获取项目中任意id的控件,控件名字就是id命名,注意是任意,下面的代码中引入虽然是

R.layout.activity_main2,但是你想要获取的控件能够不只是从这个R.layout.activity_main2 中的其中一个,而是项目下的任意id控件
,所以当你写的控件不是这里引入的 R.layout.activity_main2 其中一个,就会崩溃报错,所以这种绑定机制很容易造成人为写代码引起的错误

class MainActivity : AppCompatActivity() {

    var  textBinding  : TextBinding?  = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       
        setContentView(R.layout.activity_main2)
        
        
        //启用绑定机制后,可以直接获取项目中任意id的控件,控件名字就是id命名。
        text_number.text
        

    }

}
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">



        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text_number"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值