MVVM之DataBinding布局使用自定义View
程序员文章站
2022-07-02 20:31:09
...
某日,我打算用databinding写一个布局,体验一下MVVM的快乐,于是,发生了接下来的故事。
我要实现的大概是这么一个布局:
于是,我首先写了这么一个自定义的组合控件
class SpecialText : ConstraintLayout {
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context, attrs, defStyleAttr
) {
initView(context, attrs)
}
private fun initView(context: Context, attrs: AttributeSet) {
LayoutInflater.from(context).inflate(R.layout.view_special_text, this, true)
val mTypeArray =
context.obtainStyledAttributes(attrs, R.styleable.SpecialText)
val text0 = mTypeArray.getString(R.styleable.SpecialText_showTexta)
val text1 = mTypeArray.getString(R.styleable.SpecialText_showTextb)
mTypeArray.recycle()
if (text0 != null) {
specialText0.text = text0
}
if (text1 != null) {
specialText1.text = text1
}
}
}
非常简单的标题以及描述内容,接着,写databinding布局:
<?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">
<data>
<variable
name="viewModel"
type="com.hyt.cupcake.view.activity.developer.DeveloperViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.activity.developer.DeveloperActivity">
<com.july.viewlibrary.customView.viewGroup.SimpleTitle
android:id="@+id/developerTitle0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleName="开发者设置" />
<com.hyt.SpecialText
android:id="@+id/developerText0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/developerTitle0"
app:showTexta="厂商品牌" />
<com.hyt.SpecialText
android:id="@+id/developerText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="@+id/developerText0"
app:layout_constraintTop_toBottomOf="@+id/developerText0"
app:showTexta="设备型号"
app:showTextb="@{viewModel.brand}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
一切似乎都很美好,activity里的代码就只是这些:
class DeveloperActivity : BaseActivity() {
private lateinit var databinding : ActivityDeveloperBinding
private val viewModel by viewModels<DeveloperViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
databinding = DataBindingUtil.setContentView(this,R.layout.activity_developer)
initView()
}
private fun initView() {
databinding.viewModel = viewModel
}
}
把布局换成databinding,并把viewModel设置进去
这个是我的ViewModel:
class DeveloperViewModel: ViewModel() {
val brand = MutableLiveData(Build.BRAND) //厂商品牌
val device = MutableLiveData(Build.DEVICE) //设备型号
val flavor = MutableLiveData(BuildConfig.FLAVOR) //渠道
val imei = MutableLiveData(Common.getIMEI()) //imei
val model = MutableLiveData(Build.MODEL) //手机型号
// val oaid = MutableLiveData(Build.MODEL) //oaid
val system = MutableLiveData("安卓 ${Build.VERSION.RELEASE}") //系统版本
}
ok,点击运行,哦吼,怎么会这样
这问题其实之前就遇到过,不过当时项目紧急,就直接使用了其他的方案,检查了一下代码,之后,我写了一个TextView,并把使用ViewModel的自定义View注释掉
<?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">
<data>
<variable
name="viewModel"
type="com.hyt.cupcake.view.activity.developer.DeveloperViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.activity.developer.DeveloperActivity">
<com.july.viewlibrary.customView.viewGroup.SimpleTitle
android:id="@+id/developerTitle0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleName="开发者设置" />
<com.hyt.SpecialText
android:id="@+id/developerText0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/developerTitle0"
app:showTexta="厂商品牌" />
<!-- <com.hyt.SpecialText
android:id="@+id/developerText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="@+id/developerText0"
app:layout_constraintTop_toBottomOf="@+id/developerText0"
app:showTexta="设备型号"
app:showTextb="@{viewModel.brand}" />-->
<TextView
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="@+id/developerText0"
app:layout_constraintTop_toBottomOf="@+id/developerText0"
android:text="@{viewModel.brand}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
运行:
妙啊,接下来(一顿搜索…databinding找不到bindingImpl类,databinding与自定义控件…)
我又尝试了把项目的主build文件,所有模块的build都删掉,Clean Project之后Rebuild Project,但都无济于事,包括类名可能出现的问题,以及include布局时,要引用变量,但如果这么做多次使用布局就没法了。
难道,快乐就到此为止了吗!
那肯定是不可以的,
我首先看了看布局,发现自定义的控件是的属性是app开头的,而TextView的text属性,是android开头的,难道,app开头的属性就是不配吗,我们天生就低人一等吗?啊不是吧啊sir!
不服输的我接下来找到了ActivityDeveloperBindingImpl这个类,找到了给TextView使用viewmodel的值的地方
嗯~妙哉,接着一顿思考,然后灵光一现,接着我给自定义控件加了这么两个set方法
package com.hyt
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import kotlinx.android.synthetic.main.view_special_text.view.*
/**
* author : Hyt
* time : 2020/09/14
* version : 1.0
* 显示对应文本和信息
* 格式:
* 姓名 阿水
*/
class SpecialText : ConstraintLayout {
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context, attrs, defStyleAttr
) {
initView(context, attrs)
}
private fun initView(context: Context, attrs: AttributeSet) {
LayoutInflater.from(context).inflate(R.layout.view_special_text, this, true)
val mTypeArray =
context.obtainStyledAttributes(attrs, R.styleable.SpecialText)
val text0 = mTypeArray.getString(R.styleable.SpecialText_showTexta)
val text1 = mTypeArray.getString(R.styleable.SpecialText_showTextb)
mTypeArray.recycle()
if (text0 != null) {
specialText0.text = text0
}
if (text1 != null) {
specialText1.text = text1
}
}
fun setShowTexta(str: String){
specialText0.text = str
}
fun setShowTextb(str: String){
specialText1.text = str
}
}
可以了,只要添加属性的set方法就ok了,嗯,真好,又可以继续快乐下去了