ViewBinding - Jetpack 视图绑定委托封装及使用示例

2023-05-16

通过视图绑定功能,您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。

在大多数情况下,视图绑定会替代 findViewById

⚠️ Kotlin Android Extensions 已弃用,这意味着不再支持使用 Kotlin 合成进行视图绑定。 如果您的应用使用 Kotlin 合成进行视图绑定,请迁移到 Jetpack 视图绑定。

#1. 设置说明

视图绑定功能可按模块启用。要在某个模块中启用视图绑定,请将 viewBinding 元素添加到其 build.gradle 文件中,如下例所示:

android {
        ...
        viewBinding {
            enabled = true
        }
    }
    

如果您希望在生成绑定类时忽略某个布局文件,请将 tools:viewBindingIgnore="true" 属性添加到相应布局文件的根视图中:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >

        ...
</LinearLayout>

#2. 用法

简单使用:可参考 ViewBinding-视图绑定用法

我有在网上找到封装好的写法,这里借鉴分享一下:委托 Android 视图绑定以及使用示例

这里我也贴一份出来:

#3. 封装

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.viewbinding.ViewBinding
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * Activity 绑定委托,可以从 onCreate 到 onDestroy(含)使用
 */
inline fun <T : ViewBinding> AppCompatActivity.viewBinding(crossinline factory: (LayoutInflater) -> T) =
    lazy(LazyThreadSafetyMode.NONE) {
        factory(layoutInflater)
    }

/**
 * Fragment 绑定委托,可以从 onViewCreated 到 onDestroyView(含)使用
 */
fun <T : ViewBinding> Fragment.viewBinding(factory: (View) -> T): ReadOnlyProperty<Fragment, T> =
    object : ReadOnlyProperty<Fragment, T>, DefaultLifecycleObserver {
        private var binding: T? = null

        override fun getValue(thisRef: Fragment, property: KProperty<*>): T =
            binding ?: factory(requireView()).also {
                // 如果在 Lifecycle 被销毁后访问绑定,则创建新实例,但不要缓存它
                if (viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
                    viewLifecycleOwner.lifecycle.addObserver(this)
                    binding = it
                }
            }

        override fun onDestroy(owner: LifecycleOwner) {
            binding = null
        }
    }

/**
 * 实现 onCreateDialog 的 DialogFragment 的绑定委托(像活动一样,它们没有单独的视图生命周期),
 * 可以从 onCreateDialog 到 onDestroy(包括)使用
 */
inline fun <T : ViewBinding> DialogFragment.viewBinding(crossinline factory: (LayoutInflater) -> T) =
    lazy(LazyThreadSafetyMode.NONE) {
        factory(layoutInflater)
    }

/**
 * 不是真正的委托,只是 RecyclerView.ViewHolders 的一个小帮手
 */
inline fun <T : ViewBinding> ViewGroup.viewBinding(factory: (LayoutInflater, ViewGroup, Boolean) -> T) =
    factory(LayoutInflater.from(context), this, false)

/**
 * 不是真正的委托,只是 CustomView 的一个小帮手
 */
inline fun <T : ViewBinding> ViewGroup.viewBinding(
    factory: (LayoutInflater, ViewGroup, Boolean) -> T,
    attachToRoot: Boolean = false
) = factory(LayoutInflater.from(context), this, attachToRoot)

#4. 使用场景示例

1. Activity中使用:

class MainActivity : AppCompatActivity() {
    private val binding by viewBinding(ActivityMainBinding::inflate)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.button.text = "Bound!"
    }
}

2. Fragment中使用:

// 不要忘记在 Fragment 构造函数中传递 layoutId

class RegularFragment : Fragment(R.layout.fragment) {
    private val binding by viewBinding(FragmentBinding::bind)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button.text = "Bound!"
    }
}

3.DialogFragment中使用:(两种写法)

// 带有 onCreateDialog 的 DialogFragment 没有视图生命周期,所以我们需要一个不同的委托

class DialogFragment1 : DialogFragment() {
    private val binding by viewBinding(FragmentBinding::inflate)

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        binding.button.text = "Bound!"
        return AlertDialog.Builder(requireContext()).setView(binding.root).create()
    }
}
// 对于具有完整视图的 DialogFragment,我们可以使用常规的 Fragment 委托(实际上是这里的整个代码与在 RegularFragment 中的完全一样)
// 注意:最近才添加了具有 layoutId 的构造函数(在 Fragment 1.3.0 中)

class DialogFragment2 : DialogFragment(R.layout.fragment) {
    private val binding by viewBinding(FragmentBinding::bind)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button.text = "Bound!"
    }
}

4.DialogFragment中使用:(三种写法)

// 对于 RecyclerView,我们不需要任何委托,只需要一个属性。
// 不幸的是,这里我们有一个名称重载:View Binding vs “binding” holder to data (onBindViewHolder)。
// ViewGroup.viewBinding() 辅助函数可以稍微减少样板。

class Adapter1 : ListAdapter<String, Adapter1.Holder>(Differ()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        return Holder(parent.viewBinding(ListItemBinding::inflate))
    }

    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.binding.textView.text = getItem(position)
    }

    class Holder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root)

    private class Differ : DiffUtil.ItemCallback<String>() { ... }
}
// 或者,我们可以为所有适配器使用通用 BoundHolder

class Adapter2 : ListAdapter<String, BoundHolder<ListItemBinding>>(Differ()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BoundHolder<ListItemBinding> {
        return BoundHolder(parent.viewBinding(ListItemBinding::inflate))
    }

    override fun onBindViewHolder(holder: BoundHolder<ListItemBinding>, position: Int) {
        holder.binding.textView.text = getItem(position)
    }

    private class Differ : DiffUtil.ItemCallback<String>() { ... }
}

open class BoundHolder<T : ViewBinding>(val binding: T) : RecyclerView.ViewHolder(binding.root)
// 就我个人而言,我更喜欢将视图创建和操作封装在 ViewHolder 中。
// 在这种情况下,BoundHolder 可以用作超类。

class Adapter3 : ListAdapter<String, Adapter3.Holder>(Differ()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = Holder(parent)

    override fun onBindViewHolder(holder: Holder, position: Int) = holder.bind(getItem(position))

    class Holder(parent: ViewGroup) : BoundHolder<ListItemBinding>(parent.viewBinding(ListItemBinding::inflate)) {

        fun bind(item: String) {
            binding.textView.text = item
        }
    }

    private class Differ : DiffUtil.ItemCallback<String>() { ... }
}

abstract class BoundHolder<T : ViewBinding>(protected val binding: T) : RecyclerView.ViewHolder(binding.root)

5.自定义View中使用:

class CustomLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private val binding: ViewCustomLayoutBinding by lazy {
        viewBinding(
            ViewCustomLayoutBinding::inflate,
            true
        )
    }

    init{
        binding.textView.text = "Test"
    }
}

具体的项目架构地址:MVVM-Project-Hilt

(欢迎讨论) 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ViewBinding - Jetpack 视图绑定委托封装及使用示例 的相关文章

  • Android ViewBinding 替换 findViewById 的神器

    ViewBinding中文官网 ViewBinding 的出现就是为了替代 findViewById 的 以前我们写完布局后就要在代码中使用 findViewById 方法找到 xml 文件中对应的 view xff0c 这样耗时费力 xf
  • kotlin-android-extensions过时了,迁移到ViewBinding

    前言 回顾历史 xff0c kotlin android extensions插件让我们省去了很多findViewById的代码 xff0c 直接使用控件id操作控件 不过在Android Studio 4 1及以上IDE新建项目的时候 x
  • ViewBinding - Jetpack 视图绑定委托封装及使用示例

    通过视图绑定功能 xff0c 您可以更轻松地编写可与视图交互的代码 在模块中启用视图绑定之后 xff0c 系统会为该模块中的每个 XML 布局文件生成一个绑定类 绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用 在大多数情况下
  • Android框架 使用ViewBinding和ButterKnife

    ButterKnife 10 2 3 Github 网站 xff1a https github com JakeWharton butterknife 进入 github 网站就可以看到 xff1a Attention This tool
  • ViewBinding的用法

    1 启用Viewbinding功能 xff1a 在模块build gradle文件android节点下添加如下代码 android span class token punctuation span span class token pun
  • Android开发:Fragment中优雅使用ViewBinding【Java】

    目录 前言 官网示例 封装 前言 ViewBinding可以帮助我们减少代码中的大部分findViewById xff0c 官网中提到了它的优点和缺点 xff1a Null 安全 xff1a 由于视图绑定会创建对视图的直接引用 xff0c
  • 是时候拥抱ViewBinding了~

    是时候拥抱ViewBinding了 xff01 xff01 一 前言二 初识ViewBinding三 拥抱ViewBinding3 1 环境要求3 2 开启ViewBinding功能3 3 Activity中ViewBinding的使用3
  • Android--Jetpack的使用(一)

    目录 1 ViewModel 2 ViewModel 43 LiveData 3 ViewModel 43 LiveData 43 dataBinding 4 ViewModel 43 SavedStateHandle 43 LiveDat
  • Jetpack-Compose-自定义绘制

    上节课我们简单的利用了一下自定义裁剪和自定义就能玩出如下简单案例 效果不错 这节课咋们来看看Compose自定义绘制能不能花里胡哨 一 Compose自定义 自定义 一个应用的可创造性往往离不开人们的千奇百怪想象和用户变化万千的需求 自定义
  • JetPack-Compose - Flutter 动态UI?

    一 Flutter 初遇 2018 06月左右入坑Flutter 于是拿出美团和痘印等好看的界面感受了一波Flutter UI和绘制等写了三天的Demo也感受到了Flutter强大 当时匆匆忙忙就写了相关Demo上传了Github 不知不觉
  • Jetpack Compose 从入门到入门(四)

    本篇开始介绍Jetpack Compose 中常用的组件 有一部分之前的文章中也出现过 xff0c 今天详细说明一下 1 Text 日常最常用的应该就是显示文字 xff0c 所以有必要说一下Text控件 首先源码如下 xff1a span
  • Jetpack Compose 从入门到入门(九)

    本篇是Compose的手势部分 点击 添加clickable修饰符就可以轻松实现元素的点击 此外它还提供无障碍功能 xff0c 并在点按时显示水波纹效果 span class token annotation builtin 64 Comp
  • JETSON TX2镜像备份与恢复以及刷机的巨详细教程(Jetpack 4.4版本)

    摘自 xff1a https blog csdn net Feizhai2 article details 109068697 utm medium 61 distribute pc relevant t0 none task blog B
  • Jetson tx2 安装jetpack_3.3手动安装cuda9.0,cudnn7.1

    1 刷机前的准备 xff08 写在前面的话 xff09 装有Ubuntu16 04或者Ubuntu18 04的电脑 xff0c 这里说的电脑可以是台式机也可以是笔记本与TX2区分开来 xff08 电脑是16 04或者18 04无所谓 xff
  • Jetson tx2(JetPack 4.4)配置pytorch环境

    下载pytorch 下载pytorch1 7 xff1a 我的系统是JetPack4 4 xff0c 要求pytorch gt 61 1 7 安装pytorch span class token function sudo span spa
  • Android Jetpack新成员Compose尝鲜

    前言 Compose的alpha版已经出来有段时间了 前不久的GDG上郭神介绍了Hilt 没曾想居然没有Compose和4 2版本的studio介绍 Compose是google今年在jetpack里新增的一位成员 想着能越过传统的xml
  • Jetpack-Compose 学习笔记(五)—— State 状态是个啥?又是新概念?

    系列第五篇 进入 Compose 中有关 State 状态的学习 前面几篇笔记讲了那么多内容 都是基于静态界面的展示来说的 即给我一个不变的数据 然后将它展示出来 如何在 Compose 中构建一个随数据而变化的动态界面呢 相信看完这篇就知
  • Jetpack-Compose之一基础使用

    一 命令式UI和申明式UI 如果之前有了解或者使用果Flutter 应该会对命令式UI这种架构不陌生 目前申明式UI确实是很火包含Flutter SwiftUI JetpackCompose都使用了该种方式 2021年7月底 Google
  • 【Android】ViewBinding+DataBinding+MVVM新手快速上手

    为什么写这篇博客 网上大部分博客 代码量都比较大 把实际的业务都代入进去了 这篇博客的目的 就是为了讲解基本原理和使用思路 然后给出一个最简单的Demo 这里不讲解具体用法 那样篇幅会太长 直接看Demo代码就行 什么是ViewBindin
  • Nvidia TX2 刷机教程 JetPack-L4T-3.0-linux-x64.run

    前言 本教程特别针对刷机被墙的朋友 如果没有被墙 其实按照官方文档一步一步操作就行 这期间我参考了特别多的网页 也去nvidia官方论坛问过 其实截止到2019年2月16日 jetpack3 3 是可以很轻松的被装上的 主要是3 0被墙 而

随机推荐

  • Springboot Netty 实现自定义协议

    Netty是由JBOSS提供的一个java开源框架 xff0c 现为 Github上的独立项目 Netty提供异步的 事件驱动的网络应用程序框架和工具 xff0c 用以快速开发高性能 高可靠性的网络服务器和客户端程序 也就是说 xff0c
  • Netty 单机百万连接测试

    1 Netty框架简介 1 1 Netty简介 netty是jboss提供的一个java开源框架 xff0c netty提供异步的 事件驱动的网络应用程序框架和工具 xff0c 用以快速开发高性能 高可用性的网络服务器和客户端程序 也就是说
  • Grafana 可视化展示容器日志

    1 进入 dashboard 2 选择对应模板 3 选择相应的服务 4 关键词检索
  • 云服务的三种模式:SaaS、PaaS、IaaS

    云服务的三种模式 1 SaaS xff08 软件即服务 xff09 SaaS xff08 Software as a Service xff09 xff0c 即软件即服务 提供给消费者完整的软件解决方案 xff0c 你可以从软件服务商处以租
  • 三种方式实现Java生产者与消费者

    一 什么是生产者与消费者 生产者与消费者是java并发环境下常见的设计模式 xff0c 一个线程负责生产数据 xff0c 一个线程负责消费数据 xff0c 两个线程同时去操作这个变量 xff0c 但是这是两个相互互斥的操作 二 代码演示 1
  • XML解析为Document对象

    XML解析为Document对象 我们在上一篇Spring源码分析中有提到 xff0c Spring是将xml文件的InputStream转换为DOM树 xff0c 然后在将DOM树解析转换为BeanDefinition从而注册bean x
  • java生产者消费者模型

    前言 生产者和消费者问题是线程模型中的经典问题 xff1a 生产者和消费者在同一时间段内共用同一个存储空间 xff0c 生产者往存储空间中添加产品 xff0c 消费者从存储空间中取走产品 xff0c 当存储空间为空时 xff0c 消费者阻塞
  • 医疗保健领域的 7 个拯救生命的 AI 用例。从早期疾病检测到增强医疗决策再到更好的患者治疗效果——这就是人工智能技术如何改变医疗保健行业。

    目录 1 肺部疾病的 AI 辅助胸部 X 线分析 新冠肺炎 肺癌 2 黑色素瘤的皮肤科扫描 3 人工智能和机器学习的 CT 和 MRI 扫描分析 4 人工智能辅助乳腺癌检测 5 数字病理学的人工智能 6 使用自然语言处理实现医疗保健管理任务
  • poj3101——Astronomy(大数数学&gcd)

    Astronomy Time Limit 2000MS Memory Limit 65536KTotal Submissions 5932 Accepted 1337 Description There are n planets in t
  • E: Unable to correct problems, you have held broken packages

    E Unable to correct problems you have held broken packages 问题 xff1a apt install libmysqlclient dev Reading package lists
  • 【MySQL】mysqldump 数据库备份mysqldump: Got error: 1449: The user specified as a definer ('root'@'%') do......

    在Linux中使用corntab 定时备份MySQL数据库 xff0c 后期因考虑安全性问题 xff0c 删除掉了 root 64 用户 xff0c 发现环境上备份报错了 mysqldump Warning Using a password
  • Android 同个工程 复制后生成两个不同的apk

    需求 xff1a 同时运行两个完全相同工程 xff0c 我们会发现手机上面只有一个apk文件 xff1f 解决 xff1a 其实我们可以改变一个工程里面的build gradle中的applicationId 的值就可以了 等再次运行两个工
  • Linux下Centos7 安装 docker总结

    本片博客只介绍在linux系统上的安装方法 本文使用 CentOS 7 6 版本 1 root权限更新Yum包 xff08 linux命令不熟悉的同学本文建议使用root权限登陆安装docker xff0c 省去很多不必要麻烦 xff09
  • 完美解决KindEditor手机弹出框显示问题

    完美解决KindEditor手机弹出框显示问题 kindeditor是非常方便简单使用的富文本编辑器 xff0c 也很符合国人的习惯 xff0c 尤其是表情等应用 xff0c 但是kindedtor在手机上的显示也是一个比较头疼的问题 xf
  • Ubuntu 18.04 设置开机自启脚本

    一 背景 同伴在频繁更新系统环境 xff0c 需要经常使用reboot命令重启 xff0c 但每次重启后端Jar都会停止 xff0c 每次重启都需要手动启动Web后端Jar包 针对此种情况 xff0c 想到了采用开机自动启动Jar包的方法来
  • 本地打印机获取以及文件打印 java

    选择相应的文件进行打印 span class hljs comment 打印文件的选择 span JFileChooser fileChooser 61 span class hljs keyword new span JFileChoos
  • sqlite 句柄-sqlite 基础教程(3)

    要操纵一个数据库你就得有一个这个数据库的句柄 又碰到这个难以理解的词了 xff0c 不过确实还没得一个更好的词来替代它 其实你跟本不需要去在乎这个词叫什么 xff0c 你只要搞清楚他是一个什么玩意儿 就如同鞋子为什么叫鞋子 xff0c 仔细
  • Python justswap自动化交易

    因为平时要在justswap上做一些自动化交易 xff0c 网上资料很少 xff0c 看了justswapapi文档之后 xff0c 发现只需要调用合约的方式就可以了 遂共享出自己的代码 span class token keyword f
  • RabbitMq学习笔记(五)—— Topic

    ReceiveTopicOne 匹配规则 span class hljs number 1 span span class hljs comment 声明交换器和队列 span channel exchangeDeclare EXCHANG
  • ViewBinding - Jetpack 视图绑定委托封装及使用示例

    通过视图绑定功能 xff0c 您可以更轻松地编写可与视图交互的代码 在模块中启用视图绑定之后 xff0c 系统会为该模块中的每个 XML 布局文件生成一个绑定类 绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用 在大多数情况下