欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MVVM之DataBinding布局使用自定义View

程序员文章站 2022-07-02 20:31:09
...

某日,我打算用databinding写一个布局,体验一下MVVM的快乐,于是,发生了接下来的故事。
我要实现的大概是这么一个布局:
MVVM之DataBinding布局使用自定义View
于是,我首先写了这么一个自定义的组合控件

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,点击运行,哦吼,怎么会这样

MVVM之DataBinding布局使用自定义View

这问题其实之前就遇到过,不过当时项目紧急,就直接使用了其他的方案,检查了一下代码,之后,我写了一个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>

运行:MVVM之DataBinding布局使用自定义View
妙啊,接下来(一顿搜索…databinding找不到bindingImpl类,databinding与自定义控件…)
我又尝试了把项目的主build文件,所有模块的build都删掉,Clean Project之后Rebuild Project,但都无济于事,包括类名可能出现的问题,以及include布局时,要引用变量,但如果这么做多次使用布局就没法了。
难道,快乐就到此为止了吗!
那肯定是不可以的,
我首先看了看布局,发现自定义的控件是的属性是app开头的,而TextView的text属性,是android开头的,难道,app开头的属性就是不配吗,我们天生就低人一等吗?啊不是吧啊sir!
不服输的我接下来找到了ActivityDeveloperBindingImpl这个类,找到了给TextView使用viewmodel的值的地方

MVVM之DataBinding布局使用自定义View
嗯~妙哉,接着一顿思考,然后灵光一现,接着我给自定义控件加了这么两个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
    }

}

MVVM之DataBinding布局使用自定义View
可以了,只要添加属性的set方法就ok了,嗯,真好,又可以继续快乐下去了

相关标签: android mvvm