我在实战过程中发现,很多重复的组件,于是我就想封装一个,咨询了我们的同事,结果果然可以按照我想的那样实现,非常棒。
在 android 中封装组件,需要以下几步:
定义 props ;
将 props 与“组件”联系起来;
集成 xml 布局;
将 props 中的值设置到 xml 中,如果需要暴露方法,在“组件”中定义即可。
1. 定义 props
在 styles.xml 文件中添加下面的内容:
其中 CustomizeProfitItem 相当于 props 的类型名称,这里的名称最好也跟“组件名称相同”;其中 attr 就是每一个属性,对应的 name 就是属性名。
2. 将 props 与“组件”联系起来
新建一个 CustomizeProfitItem 的类:
package com.example.component01
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
class CustomizeProfitItem: LinearLayout {
var label: TextView? = null
var edit: EditText? = null
var unit: TextView? = null
private var customizeLabel:String = ""
private var customizeUnit:String = ""
constructor(context: Context): this(context, null)
constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
// 得到 props 的类型名
val types = context.obtainStyledAttributes(attrs, R.styleable.CustomizeProfitItem)
// 拿到传进来的 props 值
customizeLabel = types.getString(R.styleable.CustomizeProfitItem_customize_label)!!
customizeUnit = types.getString(R.styleable.CustomizeProfitItem_customize_unit)!!
// 这个就是封装的布局文件
val view = LayoutInflater.from(getContext()).inflate(R.layout.customize_profit_item, this)
// 拿到布局中要自定义的节点
label = view.findViewById(R.id.label)
edit = view.findViewById(R.id.edit)
unit = view.findViewById(R.id.unit)
// 将 props 中的值赋值进去
label?.text = customizeLabel
unit?.text = customizeUnit
types.recycle()
}
// 可以自定义方法,方便自己
fun getEditText(): String {
return edit?.text.toString()
}
fun cleanEdit() {
edit?.text = null
}
}
需要说明的是获取属性名的时候记得带上类型名,不然找不到:
// 得到 props 的类型名
val types = context.obtainStyledAttributes(attrs, R.styleable.CustomizeProfitItem)
// 拿到传进来的 props 值,属性名的规则是:类型名_xml文件中的attr标签中的name值
customizeLabel = types.getString(R.styleable.CustomizeProfitItem_customize_label)!!
customizeUnit = types.getString(R.styleable.CustomizeProfitItem_customize_unit)!!
3. 集成 xml 布局
看上面的代码可以知道 customize_profit_item .xml 文件,就是封装的布局,我定义如下:
android:id="@+id/otherCompanySale"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
android:id="@+id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=""
android:textSize="15dp" />
android:id="@+id/edit"
android:layout_width="53dp"
android:layout_height="wrap_content"
android:autofillHints=""
android:background="@null"
android:ems="10"
android:hint="*请输入"
android:inputType="number"
android:textAlignment="textEnd"
android:textColor="#E62008"
android:textColorHint="#b4b4b4"
android:textSize="15sp" />
android:id="@+id/unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="20dp"
android:text=""
android:textSize="15sp" />
5. 根据 props 设置对应的值
在上面的 kotlin 代码中有:
val view = LayoutInflater.from(getContext()).inflate(R.layout.customize_profit_item, this)
label = view.findViewById(R.id.label)
edit = view.findViewById(R.id.edit)
unit = view.findViewById(R.id.unit)
label?.text = customizeLabel
unit?.text = customizeUnit
6. 使用封装的组件
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:id="@+id/item1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:customize_label="测试1"
app:customize_unit="尾部1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
android:id="@+id/customizeProfitItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:customize_label="测试2"
app:customize_unit="尾部2"
app:layout_constraintTop_toBottomOf="@+id/item1"
app:layout_constraintLeft_toLeftOf="parent"/>
效果如下:
简单的demo