Android——ViewBinding总结

2023-05-16

ViewBinding

一旦启动了ViewBinding功能之后,Android Studio会自动为我们所编写的每一个布局文件都生成一个对应的Binding类。

启用ViewBinding需要在app/build.gradle中添加

<!--build.gradle-->
android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Binding类的命名规则是将布局文件按驼峰方式重命名后,再加上Binding作为结尾。
比如说,我们定义一个activity_main.xml布局,那么与它对应的Binding类就是ActivityMainBinding。

当然,如果有些布局文件你不希望为它生成对应的Binding类,可以在该布局文件的根元素位置加入如下声明:

<LinearLayout
    xmlns:tools="http://schemas.android.com/tools"
    ...
    tools:viewBindingIgnore="true">
    ...
</LinearLayout>

1. 在Activity中使用ViewBinding

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityFirstBinding.inflate(layoutInflater)
        setContentView(binding.root)    //from getRoot()
        binding.button1.text = "Hello World!"
        binding.button1.setOnClickListener {
            Toast.makeText(this, "Button clicked.", Toast.LENGTH_SHORT).show()
        }
    }
}

如果需要在onCreate()函数之外的地方对空间进行控制,将binding变量声明为全局变量
Kotlin声明的变量都必须在声明的同时对其进行初始化。而这里我们显然无法在声明全局binding变量的同时对它进行初始化,所以这里又使用了lateinit关键字对binding变量进行了延迟初始化。

class FirstActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFirstBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFirstBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.button1.text = "Hello World!"
        binding.button1.setOnClickListener {
            Toast.makeText(this, "Button clicked.", Toast.LENGTH_SHORT).show()
        }
    }
}

2. 在Fragment中使用ViewBinding

通过以下方法来实现在MainFragment中显示布局

class MainFragment : Fragment(){
    //属性名前加下划线通常意味着不打算直接访问该属性
    private var _binding : FragmentMainBinding? = null
    //get()意味着返回_binding!!给getBinding()函数
    val binding get() = _binding!!
    override fun onCreateView(inflater : LayoutInflater, container : ViewGroup?, savedInstanceState : Bundle?) : View{
        _binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    }
    override fun onDestroyView(){
        super.onDestroyView()
        _binding = null
    }
}

由于我们是在onCreateView()函数中加载的布局,那么理应在与其对应的onDestroyView()函数中对binding变量置空,从而保证binding变量的有效生命周期是在onCreateView()函数和onDestroyView()函数之间

3. 在Adapter中使用ViewBinding

假设我们定义了fruit_item.xml来作为RecyclerView的子项布局
编写如下RecyclerView Adapter来加载和显示这个子项布局

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
}

接下来在Adapter中使用ViewBinding

class FruitAdapter(val fruitList : List<Fruit>) : RecyclerView.Adapter<FruitAdapter.ViewHolder>(){
    inner class ViewHolder(binding : FruitItemBinding) : RecyclerView.ViewHolder(binding.root){
        val fruitImage : ImageView = binding.fruitImage
        val fruitName : TextView = binding.fruitName
    }
    override fun onCreateViewHolder(parent : ViewGroup, ViewType : Int) : ViewHolder{
        val binding = FruitItemBinding.inflate(LayoutInflter.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
}
  1. 我们在onCreateViewHolder()函数中调用FruitItemBinding的inflate()函数去加载fruit_item.xml布局文件。
  2. 接下来需要改造ViewHolder,让其构造函数接收FruitItemBinding这个参数。但是注意,ViewHolder的父类RecyclerView.ViewHolder它只会接收View类型的参数,因此我们需要调用binding.root获得fruit_item.xml中根元素的实例传给RecyclerView.ViewHolder。

4. 对引入布局使用ViewBinding

假设我们有一titlebar.xml作为通用布局引入到其他布局中
1. 使用include引入布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    ...
    <include 
    <!--在include的时候给被引入的布局添加一个id,ViewBinding便可以关联到titlebar.xml中的控件-->
        android:id="@+id/titleBar"
        layout="@layout/titlebar" />
    ...
</LinearLayout>
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.titleBar.title.text = "Title"
        binding.titleBar.back.setOnClickListener {
        }
        binding.titleBar.done.setOnClickListener {
        }
    }
}

2. 使用merge引入布局
使用merge标签引入的布局在某些情况下可以减少一层布局的嵌套,而更少的布局嵌套通常就意味着更高的效率

<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="Back" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Title"
        android:textSize="20sp" />
    <Button
        android:id="@+id/done"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:text="Done" />
</merge>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    ...
    <include
        layout="@layout/titlebar" />
    ...
</LinearLayout>
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    //TitlebarBinding就是Android Studio根据我们的titlebar.xml布局文件自动生成的Binding类
    private lateinit var titlebarBinding: TitlebarBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        titlebarBinding = TitlebarBinding.bind(binding.root)
        setContentView(binding.root)
        titlebarBinding.title.text = "Title"
        titlebarBinding.back.setOnClickListener {
        }
        titlebarBinding.done.setOnClickListener {
        }
    }
}

5. 在自定义控件中使用ViewBinding

自定义导航栏

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/title_bg">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/titleBack"
        android:text="back"
        android:layout_margin="5dp"
        android:background="@drawable/back_bg"
        android:textColor="#fff"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/titleText"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="Title Text"
        android:textColor="#fff"
        android:textSize="24sp"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/titleEdit"
        android:text="Edit"
        android:layout_margin="5dp"
        android:background="@drawable/edit_bg"
        android:textColor="#fff"/>
</LinearLayout>

添加自定义控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.android.widgettest.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

使用ViewBinding

class TitleLayout(context : Context, attrs : AttributeSet) : LinearLayout(context, attrs) {
    var binding : TitleBinding
    init {
        //inflate(layoutInflater, parent, attachToParent)
        binding = TitleBinding.inflate(LayoutInflater.from(context), this, true)
        binding.titleBack.setOnClickListener {
            val activity = context as Activity
            activity.finish()
        }
        binding.titleEdit.setOnClickListener {
            Toast.makeText(context, "Edit", Toast.LENGTH_SHORT).show()
        }
    }
}

6. 在Activity中获取fragment的binding对象

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/leftFrag"
        android:name="com.android.fragment.LeftFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"/>
</LinearLayout>

fragment_one.xml

<?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="match_parent">
    <Button
        android:id="@+id/button"
        android:layout_gravity="center_horizontal"
        android:text="button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

OneFragment.kt

class OneFragment : Fragment() {
    private var _binding : LeftFragmentBinding? = null
    //此处设置为public,这样可以在Activity中获取_binding
    val binding get() = _binding!!
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = LeftFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    lateinit var binding : ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        //先获取fragment实例
        val leftFrag = supportFragmentManager.findFragmentById(R.id.leftFrag) as LeftFragment
        //通过fragment实例获取binding
        leftFrag.binding.button.setOnClickListener {
            Log.d("TestBtn", "clicked")
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android——ViewBinding总结 的相关文章

  • Android 覆盖在软件按钮之上

    我正在尝试编写一个绘制自定义鼠标指针的应用程序 我目前有一个服务 它创建一个扩展 ViewGroup 的类 并使用 WindowManager 系统服务将其显示为带有 FLAG LAYOUT IN SCREEN 设置的 TYPE SYSTE
  • 通过数据绑定将字符串传递到包含的布局不起作用

    我正在尝试使用 Android 数据绑定功能将一个简单的字符串从我的主布局传递到布局 它编译得很好 但传递给包含的值实际上并未传递 即 它没有出现在我的布局中
  • 如何检测和管理来电(Android)?

    我想创建一个应用程序 可以检测来电并在一定数量的蜂鸣声 响铃 后启动我的自定义活动 我的意思是在 2 或 3 或 5 声蜂鸣声 响铃 后我的activity被触发 我该怎么做 Thanks 我认为您无法计算自来电开始以来电话响了多少次 无法
  • Android中如何使用洪水填充算法?

    我是Android编程新手 最近尝试编写一个简单的应用程序 仅供练习 在这个中 我想在用户点击时为图像着色 但我不知道如何开始 我读过不同的主题 其中提到使用 洪水填充 算法 我在网上找到了它 但我不知道如何将它放入我的简单应用程序中 我找
  • 显示警报或收到通知时的视图

    我正在关注this http tokudu com 2010 how to implement push notifications for android 显示的教程通知 on an 安卓设备 当我在设备上运行该应用程序时 状态栏上会出现
  • AppCompat v21 工具栏更改徽标大小

    我正在从以前的操作栏迁移到 appcompat v21 中的新工具栏功能 我仍然想将徽标保留在操作栏 工具栏 的左上角 为此 我在布局中添加了支持工具栏 并为其创建了一个新的工具栏 app theme style NewToolBarSty
  • 按钮未显示在屏幕上

    我创建了一个应用程序 其中显示带有图像和文本的列表视图 我在页面末尾添加按钮 但这没有显示在屏幕上 我是 Android 新手 我该如何解决这个问题 这是我的 UI XML 代码
  • Android Studio - 如何关闭“单词‘word’中的拼写错误?”

    当命名变量或给出字符串参数时 Android Studio 似乎对我如何标记事物有问题 有办法把它关掉吗 是的 打开Preferences gt Editor gt Inspections gt Spelling gt 关闭Typo并按OK
  • android 确定设备是否采用从右到左的语言/布局

    有没有办法确定设备是否使用从右到左的语言 例如阿拉伯语 而不是从左到右的语言 英语 与较旧的 API 级别 低至 10 兼容的东西是必要的 SOLUTION 我最终在接受的答案中使用了 xml 方法 接下来 我还添加了此处指示的代码 以应对
  • AnalyticsService 未在应用程序清单中注册 - 错误

    我正在尝试使用 sdk 中提供的以下文档向 Android 应用程序实施谷歌分析服务 https developers google com analytics devguides collection android v4 https d
  • 没有调用addToBackStack,片段仍然添加到backstack,为什么?

    我正在制作我的片段更换器助手类 但我遇到了一些问题 我称之为FragmentChanger 它有一个fragmentContainer 这是一个ViewGroup 其中包含我想展示的所有片段 我已经做了我自己的replace Fragmen
  • Integer.parseInt("0x1F60A") 以 NumberformatException 结束

    我尝试从数据库中获取长字符串内的表情符号代码 格式如下 0x1F60A 所以我可以访问代码 但它将是String 起初 我尝试通过执行以下操作来转换变量tv setText beforeEmo getEmijoByUnicode int e
  • 在 AppAuth-Android 中注销

    我有一个用JAVA开发的Android应用程序 对于这个应用程序 我使用的是身份服务器4 https github com IdentityServer IdentityServer4作为我的 STS 一切正常 但我找不到任何注销的实现Ap
  • 通过列表视图检查动态生成的复选框时遇到问题

    我知道其他成员已经提出了这个问题 一些成员也给出了解决方案 但问题是我没有找到任何适合我的应用程序的解决方案 我正在创建一个应用程序 其中我有一个屏幕 它将显示动态列表视图 其中包含列表项 复选框和三个文本视图 一个用于候选人姓名 另外两个
  • 从手机访问本地主机[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在使用
  • Ionic Facebook Api 无效密钥哈希

    我无法让我的应用程序允许 Facebook 登录 每次用户尝试登录 Facebook 并使用他们的 FB 验证我的应用程序时 都会出现以下错误 无效的密钥哈希 它们的密钥哈希 xxxxxxxxxx 与任何存储的密钥哈希不匹配 配置您的应用程
  • 内部存储的安全性如何?

    我需要的 对于 Android 我需要永久保存数据 但也能够编辑 并且显然是读取 它 用户不应访问此数据 它可以包含诸如高分之类的内容 用户不得对其进行编辑 我的问题 我会 并且已经 使用过Internal Storage 但我不确定它实际
  • 检测 ListView(或 ScrollView)内的滚动位置

    我正在构建一个聊天室应用程序 其中每 X 秒就会轮询一次新事件 每次发生这种情况时 此代码都会使用新数据更新 RoomAdapter ArrayAdapter 的自定义子类 并将其滚动到底部 RoomAdapter adapter Room
  • Android:确定 2.2 及更高版本上的摄像头数量

    我的应用程序需要在 Android 2 2 及更高版本上运行 我需要一种方法来确定可用摄像机的数量 有很多帖子解决了这个问题 但我找不到一个有效的 一种解决方案是简单地检测操作系统版本 任何 2 2 版本的设备都仅限于 1 个摄像头 即使该
  • Android - iphone 风格 tabhost [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐

  • 【C++】多线程(链式、循环队列)实现生产者消费者模式

    生产者消费者模式 xff1a 生产者消费者问题 xff08 英语 xff1a Producer consumer problem xff09 xff0c 也称有限缓冲问题 xff08 英语 xff1a Bounded buffer prob
  • windows10+ubuntu双系统开机引导界面不见的解决办法

    windows10 43 ubuntu双系统开机引导界面不见的解决办法 在两年之前 xff0c 因为某个项目的需要 xff0c 下载了ubuntu16 04的系统 xff0c 构成了win10 43 ubuntu的双系统 然后每次开机都要不
  • 生产者消费者模型(Qt实现)

    Qt实现生产者消费者模型 本文展示的是用Qt实现的生产者消费者模型 该模型含有4个生产者 xff0c 4个消费者 xff0c 12个缓冲区 当缓冲区放满产品时 xff0c 生产者进程阻塞 当缓冲区无产品时 xff0c 消费者进程阻塞 点击
  • Spring简介

    一 spring简介 1 1 1 Spring是什么 Spring是分层的 Java SE EE应用full stack轻量级开源框架 xff0c 以IoC Inversion of Control 反转控制 xff09 和AOP Aspe
  • 开启虚拟机(centos7)没有ens33 ip地址的解决方法(已解决)

    当我们启动虚拟机 输入ifconfig查看IP地址时 出现下图这样的情况 发现没有ens33 切换到 etc sysconfig network scripts 目录并编辑ifcfg ens33 cd etc sysconfig netwo
  • Datawhale数据分析第二章第一节:数据清洗及特征处理

    回顾 amp 引言 前面一章的内容大家可以感觉到我们主要是对基础知识做一个梳理 xff0c 让大家了解数据分析的一些操作 xff0c 主要做了数据的各个角度的观察 那么在这里 xff0c 我们主要是做数据分析的流程性学习 xff0c 主要是
  • androidx指纹验证

    安卓使用androidx BiometricPrompt实现指纹验证 androidsdk版本大于29之后 xff0c 使用FingerprintManagerCompat进行指纹验证显示被废弃 xff0c FingerprintManag
  • ios app真机测试到上架App Store详细教程-必看

    转载 xff1a https blog csdn net p312011150 article details 89374401 ios app真机测试到上架App Store详细教程 必看 Appuploader常见问题 转存失败 重新上
  • 启动Ps提示找不到VCRUNTIME140_1.dll的故障解决办法

    如果电脑之前安装过ps xff0c 卸载后重新安装可能会遇到运行库的问题 xff0c 导致无法打开 打开ps xff0c 报如下错误 由于找不到VCRUNTIME140 1 dll xff0c 无法继续执行代码 重新安装程序可能会解决此问题
  • maven+mybatis安装与配置

    maven的安装与配置 maven的安装 下载地址 xff1a https maven apache org 进入官网 点击左侧DOWNLOAD 下翻找到apache maven 3 8 3 bin zip xff0c 点击下载 下载后解压
  • 力扣 1170. 比较字符串最小字母出现频次 C++

    我们来定义一个函数 f s xff0c 其中传入参数 s 是一个非空字符串 xff1b 该函数的功能是统计 s 中 xff08 按字典序比较 xff09 最小字母的出现频次 例如 xff0c 若 s 61 dcce xff0c 那么 f s
  • Collection集合的实用工具类 -- Collections的常用方法

    1 Collection批量添加数据 addAll Collections span class token punctuation span span class token function addAll span span class
  • Python获取与处理文件路径/目录路径

    目录 文件目录结构说明一 路径获取1 1 获取当前文件的绝对路径1 2 1 获取当前文件的所在目录1 2 2 获取当前文件的所在目录的上一级目录1 3 获取当前文件名1 4 获取当前文件对于基准路径的相对路径 二 路径判断2 1 判断路径是
  • FTP服务与SSH远程管理

    目录 目录 FTP概述 FTP作用与工作原理 实验 设置用户模式登录 SSH ssh概述 SSH密钥机制 ssh实验 FTP概述 FTP File TransferProtocol xff0c 文件传输协议 是典型的C S架构的应用层协议
  • cin、cin.getline()、getline()、cin.get()、gets()、fgets()的用法区别

    写在前面 xff1a 以下为个人学习记录 xff0c 如有错误 xff0c 欢迎指出交流 xff01 一 cin gt gt 用法1 xff1a 输入一个数字或字符 span class token macro property span
  • 了解spring框架构造具体流程

    实现步骤 工程大概结构 xff1a 1 新建maven项目 修改仓库 按图设置 2 加入依赖 xff0c 修改pom xml spring context spring依赖junit pom xml lt dependencies gt l
  • yum源仓库本地搭建的两种方法

    文章目录 前言一 yum是什么 xff1f 二 配置yum源的步骤 xff08 http版 xff09 1 上传镜像文件2 备份yum源创建http repo文件3 镜像文件挂载 xff08 mount为临时挂载重启需要重新挂载 xff09
  • Statement和PreparedStatement的区别

    区别 xff1a 1 PreparedStatement可以使用占位符 xff0c 是预编译的 xff0c 批处理比Statement效率高 2 使用 Statement 对象 在对数据库只执行一次性存取的时侯 xff0c 用 Statem
  • Datawhale数据分析第二章第二节:数据重构1

    复习 xff1a 在前面我们已经学习了Pandas基础 xff0c 第二章我们开始进入数据分析的业务部分 xff0c 在第二章第一节的内容中 xff0c 我们学习了数据的清洗 xff0c 这一部分十分重要 xff0c 只有数据变得相对干净
  • Android——ViewBinding总结

    ViewBinding 一旦启动了ViewBinding功能之后 xff0c Android Studio会自动为我们所编写的每一个布局文件都生成一个对应的Binding类 启用ViewBinding需要在app build gradle中