IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> DataBinding 高级用法 -> 正文阅读

[移动开发]DataBinding 高级用法

DataBinding的高级用法的演示:
?1、双向绑定
?2、自定义属性(todo 注意databinding支持view的属性,需要有对应setXXX,getXXX的格式的函数(或者boolean的isXXX),才能被框架感知。
?如果一个View的属性,不是规范的setXXX,getXXX的设置/获取函数,那么就不行。可以继承该函数,设置setXXX/getXXX,在xml中自定义的View,就可以支持。)
?3、转换器converters
?4、自定义控件支持dataBinding,@BindingMethods、@InverseBindingMethods等

DataBinding的高级用法的问题:
?1、@{user.name}如果user为null,是否运行崩溃
?2、DataBinding是否支持所有View的属性
?3、双向绑定时候,是否会数据陷入死循环。
问题解答:
?1、如果xml中的variable没有binding赋值,如myBg那一行如果注释掉。运行时就会崩溃。而如果只是name为空,就会显示null,而不会崩溃。
?2、上面已经知道,不是所有的View的属性都可以直接dataBinding的,需要满足标准setXXX/getXXX的函数方式,或者按照[MyImageView]中注释写的那三种方法,扩展view的属性binding支持
?3、双向绑定也不会死循环,因为实现类会做old==new的value值校验,并return,避免陷入双向刷新的死循环。

1. 项目 build.gradle 添加引用库

  //SwipeRefreshLayout
  implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
  //glide
  implementation 'com.github.bumptech.glide:glide:4.12.0'
  kapt 'com.github.bumptech.glide:compiler:4.12.0'//kotlin代码需要这个kapt注入进程

2. 布局文件 activity_advanced_use.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="user"
            type="org.hanyang.jetpack.binding.bean.ObUser" />
        <!--用于加载图片的url-->
        <variable
            name="url"
            type="String" />

        <variable
            name="myBg"
            type="android.graphics.drawable.Drawable" />

        <!--用于演示双向绑定,刷新view的swipeRefreshLayout控件需要用到-->
        <variable
            name="activity"
            type="org.hanyang.jetpack.binding.activity.AdvancedUseActivity" />
    </data>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <!--1、双向绑定,使用的是@={} 下面输入框的修改,就会同步修改user的name字段-->
        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{`Name ` + user.name }"
            tools:text="在输入框修改user的name,这里会变" />

        <androidx.appcompat.widget.AppCompatEditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="这里演示的输入名字,更改为user的name"
            android:singleLine="true"
            android:text="@={user.name}" />

        <!--2、转换,也就是将原有不支持的属性,转换为支持,兼容,如 background
         的属性不能设置普通 String,这里可以通过@BindingConversion的静态函数,来适配-->
        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@{`red`}"
            android:text="这个文案的背景色属性,就是通过converters转换才行的" />

        <!--3、添加或扩展已有控件的属性,或者给它的set支持dataBinding
         因为dataBinding只是控件属性set/get,需要标准的函数命名getXXX,setXXX才会识别该属性。
         如果不是这样命名的函数属性set,就不会支持dataBinding。这里我们可以扩展兼容-->

        <!--这里的src属性,并不支持网络加载url,或者uri,我们可以在静态函数中,适配兼容-->
        <androidx.appcompat.widget.AppCompatImageView
            imgSrc="@{url}"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_marginTop="10dp"
            android:src="@drawable/img_banner1" />
        <!--这里是用的自定义的View,使用img属性,在view中添加set函数,这样和上面的@BindingAdapter对比,上面更方便,扩展性强-->
        <org.hanyang.jetpack.binding.view.MyImageView
            img="@{myBg}"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_marginTop="10dp" />
        <!--这里的 image 属性,是原控件没有的,而是通过@BindingMethods来实现函数映射-->
        <androidx.appcompat.widget.AppCompatImageView
            image="@{myBg}"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_marginTop="10dp" />

        <!--4.自定义View 双向绑定演示 记住双向绑定使用@={}-->
        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            app:sfl_refreshing="@={activity.refreshing}">

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_long_text_ad_binding"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="long text 长文本" />
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    </LinearLayout>
</layout>

3. 使用工具文件 BCTool.kt

/**
 * Binding高级用法中,辅助工具类,演示@BindingConversion,@bindadapter等
 */
object BCTool {

    /**
     * 兼容适配view的background的str转color属性,这里函数名 可以随意,而且不需要其他地方显式的调用。
     * 只需要在此 ,静态函数的声明即可。(java的写法就是public static,这里不写java版的了。)
     */
    @JvmStatic
    @BindingConversion
    fun conversionStr2Color(str: String): Drawable {
        return when (str) {
            "red" -> {
                ColorDrawable(Color.RED)
            }
            "blue" -> ColorDrawable(Color.BLUE)
            else -> {
                ColorDrawable(Color.YELLOW)
            }
        }
    }

    /**
     * 用于appCompatImageView的自定义属性,bind:imgSrc,命名空间bind:可以省略,也就是写作 imgSrc亦可。可以用于加载url的图片
     * 函数名也是随意,主要是value的声明,就是新加的属性名了,可以多个属性同用,并配置是否必须一起作用
     * 函数名随意,方法签名才重要,匹配对象控件,以及属性参数。这里还可以添加old 参数,获取修改新参数 之前对应的值。
     * todo 加载网络图片,需要网络权限,别忘了
     */
    @JvmStatic
    @BindingAdapter(value = ["imgSrc"], requireAll = false)
    fun urlImageSrc(view: AppCompatImageView, /*old: String?, */url: String?) {
        Glide.with(view)
            .load(url)
            .placeholder(R.drawable.img_banner1)
            .centerInside()
            .into(view)
    }

    /**
     * 这个是 databinding高级用法中,配合演示swipeRefreshLayout的刷新状态的感知
     * 第一步:单向的,数据变化,刷新UI
     */
    @JvmStatic
    @BindingAdapter("sfl_refreshing", requireAll = false)
    fun setSwipeRefreshing(view: SwipeRefreshLayout, oldValue: Boolean, newValue: Boolean) {
        //判断是否是新的值,避免陷入死循环
        if (oldValue != newValue)
            view.isRefreshing = newValue
    }

    /**
     * 第二步:ui的状态,反向绑定给数据变化
     */
    @JvmStatic
    @BindingAdapter("sfl_refreshingAttrChanged", requireAll = false)
    fun setRefreshCallback(view: SwipeRefreshLayout, listener: InverseBindingListener?) {
        listener ?: return
        view.setOnRefreshListener {
            //由ui层的刷新状态变化,反向通知数据层的变化
            listener.onChange()
        }
    }

    /**
     * 反向绑定的实现,将UI的变化,回调给bindingListener,listener就会onChange,通知数据变化
     * 注意这里的attr和event,是跟上面两步配合一致才有效
     */
    @JvmStatic
    @InverseBindingAdapter(attribute = "sfl_refreshing", event = "sfl_refreshingAttrChanged")
    fun isSwipeRefreshing(view: SwipeRefreshLayout): Boolean {
        return view.isRefreshing
    }
}

4. 测试页面 AdvancedUseActivity.kt

/**
 * DataBinding的高级用法的演示
 * 1、双向绑定
 * 2、自定义属性(todo 注意databinding支持view的属性,需要有对应setXXX,getXXX的格式的函数(或者boolean的isXXX),才能被框架感知。
 * 如果一个View的属性,不是规范的setXXX,getXXX的设置/获取函数,那么就不行。可以继承该函数,设置setXXX/getXXX,在xml中自定义的View,就可以支持。)
 * 3、转换器converters
 * 4、自定义控件支持dataBinding,@BindingMethods、@InverseBindingMethods等
 */
class AdvancedUseActivity : AppCompatActivity() {
    val TAG = AdvancedUseActivity::class.java.simpleName

    //标记是否刷新liveData中的对象。不能 private,因为要用在xml中
    val refreshing = MutableLiveData<Boolean>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //Glide 初始化
        //Glide.init(this, GlideBuilder())
        val binding = DataBindingUtil.setContentView<ActivityAdvancedUseBinding>(
            this,
            R.layout.activity_advanced_use
        )

        //user 设置
        val user = ObUser("张三", 30, 1, "没有修改名字前的数据")
        binding.user = user

        //url
        val url = "https://t7.baidu.com/it/u=2931491413,1199396761&fm=193&f=GIF"
        binding.url = url

        //设置myView的 img 参数
        binding.myBg = getDrawable(R.drawable.img_banner1)

        //演示自定义View实现双向绑定
        // 1、先单向绑定 也就是将viewModel的数据变化,通知UI来刷新;(这里也就是在[BCTool]中static声明自定义属性,refreshing)
        // 2、将UI的变化,反向绑定,来通知数据模型的状态变化。
        // 3、完成双向绑定,避免死循环。
        //这里是个长文本,配合演示swipeRefreshLayout的状态感知
        binding.tvLongTextAdBinding.text = strText
        //
        binding.activity = this
        //这里记录log, liveData感知,也就证明,UI的刷新,将状态反响绑定给了data
        refreshing.observe(this, Observer<Boolean> {
            Log.i(TAG, "refreshing $it")
        })
    }

}

const val strText = """
James Ray edited this page on 2 Apr · 241 revisions
Welcome to the Ethereum Wiki!
Documentation chat standard-readme compliant
Ethereum wiki covering all things related to Ethereum
Contents
Issues and pull requests
Contribution guidelines
Introduction
Fixing vandalism
Page titles
Wikipedia pillars
Translating
License and contributor license agreement
Editing locally (requires access permission)
Setup
Usage
Getting started
"""

5. 效果图

?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:17:25  更:2022-08-19 19:17:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:21:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码