介绍
本篇文章介绍ObservableFieldActivity中的知识点
observable_field_profile.xml 布局文件
<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>
<import type="com.example.android.databinding.basicsample.R"/>
<import type="com.example.android.databinding.basicsample.util.ConverterUtil"/>
<variable
name="user"
type="com.example.android.databinding.basicsample.data.ObservableFieldProfile" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/name"
...
android:text="@{user.name}"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
.../>
<TextView
android:id="@+id/lastname"
...
android:text="@{user.lastName}"/>
<!-- Layout expressions can be *too* powerful. It's preferred to avoid this type of
view logic in the layout. Instead, use Binding Adapters (see ViewModelActivity).
Also, `app:srcCompat` is bound to setImageResource.
-->
<ImageView
android:id="@+id/imageView"
...
android:tint="@{user.likes > 9 ? @color/star : @android:color/black}"
app:srcCompat="@{user.likes < 4 ? R.drawable.ic_person_black_96dp : R.drawable.ic_whatshot_black_96dp }"/>
<TextView
android:id="@+id/likes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{Integer.toString(user.likes)}"
.../>
<Button
android:id="@+id/like_button"
android:onClick="onLike"
android:text="@string/like"
.../>
<TextView
android:id="@+id/name_label"
.../>
<TextView
android:id="@+id/lastname_label"
.../>
<TextView
android:id="@+id/likes_label"
.../>
<!-- android:progressTint is only available in API 21+ so we deal with that in the
Binding Adapter.
The android:visibility attribute is used to showcase BindingConversions,
see the README for a better alternative with a BindingAdapter.-->
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:max="@{100}"
android:visibility="@{ConverterUtil.isZero(user.likes)}"
app:progressScaled="@{user.likes}"
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
1.布局文件中导入了两个类R和ConverterUtil,定义了一个变量user,user的类型是ObservableFieldProfile
name的TextView很简单的使用表达式引用user的name属性,设置给android:text,即android:text="@{user.name}"
lastname和name一样。
2.imageView的ImageView中android:tint 使用三目运算符表达式,返回tint需要的值:android:tint="@{user.likes > 9 ? @color/star : @android:color/black}"
3.app:srcCompat属性本来接收的是int类型:@drawable/xxx,但是这里传递的是R.drawable.XXX,传递的值和属性本来接收参数不一致,这时就需要使用BindingMethods自定义方法,将setImageResource和app:srcCompat属性绑定到一起。
@BindingMethods(
BindingMethod(type = ImageView::class,
attribute = "app:srcCompat",
method = "setImageResource"))
class MyBindingMethods
4.likes中 android:text接收Integer.toString(user.likes)方法,因为系统会默认import java.lang.*的类,所以Integer和String不需要导入了
5.progressBar中的android:visibility 接收到是ConverterUtil 的静态方法isZero
object ConverterUtil {
@JvmStatic fun isZero(number: Int): Boolean {
return number == 0
}
}
kotlin中的静态方法在java中使用需要添加JvmStatic注解
这个方法返回的是boolean类型,但是android:visibility 接收的是一个VISIBLE, GONE and INVISIBLE 中的一个值,所以我们需要进行类型转换:
object BindingConverters{
@BindingConversion
@JvmStatic fun booleanToVisibility(isNotVisible: Boolean): Int {
return if (isNotVisible) View.GONE else View.VISIBLE
}
}
6.app:progressScaled是自定义属性,这里的自定义方式是通过BindAdapter
@BindingAdapter(value = ["app:progressScaled", "android:max"], requireAll = true)
@JvmStatic fun setProgress(progressBar: ProgressBar, likes: Int, max: Int) {
progressBar.progress = (likes * max / 5).coerceAtMost(max)
}
coerceAtMost最大值是max(100) 所以progressBar根据likes1-5增加。
requireAll = true表示value数组中的属性要一起使用,任何一个属性发生变化都会调用这个方法。
Data类
data class ObservableFieldProfile(
val name: String,
val lastName: String,
val likes: ObservableInt
)
其中likes是ObservableInt类型,即可观察类型,当likes的值变化的时候,布局中引用likes的视图都会自动更新
Activity文件
class ObservableFieldActivity : AppCompatActivity() {
private val observableFieldProfile = ObservableFieldProfile("Ada", "Lovelace", ObservableInt(0))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ObservableFieldProfileBinding =
DataBindingUtil.setContentView(this, R.layout.observable_field_profile)
binding.user = observableFieldProfile
}
/**
* This method is triggered by the `android:onclick` attribute in the layout. It puts business
* logic in the activity, which is not ideal. See {@link ViewModelActivity} for a better
* solution.
*/
fun onLike(view: View) {
observableFieldProfile.likes.set(observableFieldProfile.likes.get() + 1)
}
}
onCreate通过binding.user = observableFieldProfile,将observableFieldProfile实例赋值给xml中的user属性。
其中onLike的注解很重要:
这种方式会把复杂的逻辑放到了Activity中,Activity本质是不处理业务的。
总结
这个页面主要展示了databinding的很多使用方式,而且这种设计模式就是我们熟悉的mvc模式,mvc的缺点,耦合性强,不易测试,不易扩展,在这里都体现了。
网友评论