这篇笔记主要记录常见的应用场景和一些基础知识点
- Activity和Fragment之间的交互(它们都有使用DataBinding)
- 定义自动生成的绑定类的名称
- 和ViewStub的搭配方法
- View的ID会在绑定类中自动生成控件的成员变量
Activity视图内包含Fragment和ViewStub
在Activity中包含Fragment和ViewStub是很常见的操作,然而DataBinding可以让他们之间的关联代码减少很多。下面的代码用来演示他们之间通过DataBinding是如何来进行交互的。
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewStubData"
type="androidx.databinding.ObservableField<String>" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".CustomBindingActivity">
<fragment
android:id="@+id/fCustomFragment"
class="com.im_hero.databinding.CustomBindingFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#2299FF"
android:text="@{viewStubData}" />
<ViewStub
android:id="@+id/viewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/custom_view_stub" />
</LinearLayout>
</layout>
这是Activity的布局文件,其中“<”符号被替换成了“<”,参考表达式语言-常见功能。它包含了一个Fragment和一个ViewStub,其中viewStubData是一个可被观察的数据,用来标识viewStub的显示状态。如下,是对应Activity的代码:
class CustomBindingActivity : AppCompatActivity(), CustomBindingFragment.CustomBindingFragmentListener {
lateinit var activityCustomBindingBinding: ActivityCustomBindingBinding
lateinit var fCustomFragment: CustomBindingFragment
lateinit var tvViewStub: TextView
lateinit var customViewStubBinding: CustomViewStubBinding
val oFieldViewStub = ObservableField(INVISIBLE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityCustomBindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_custom_binding)
activityCustomBindingBinding.viewStubData = oFieldViewStub
fCustomFragment = supportFragmentManager.findFragmentById(R.id.fCustomFragment) as CustomBindingFragment
}
/**
* [CustomBindingFragment.CustomBindingFragmentListener.showViewStub]用于让CustomBindingFragment控制ViewStub的显示状态
*/
override fun showViewStub(checked: Boolean) {
if (::tvViewStub.isInitialized) {
oFieldViewStub.set(if (checked) VISIBLE else INVISIBLE)
} else {
tvViewStub = activityCustomBindingBinding.viewStub.viewStub!!.inflate() as TextView
// 运行时绑定,因为ViewStub是在运行时并且需要了才会填充到布局内部。
customViewStubBinding = DataBindingUtil.bind(tvViewStub)!!
customViewStubBinding.viewStubData = oFieldViewStub
oFieldViewStub.set(VISIBLE)
}
}
}
运行时绑定,比较实用给ViewStub这种在运气期间加入到布局的内部的视图。
有个细节,如下代码中第一个viewStub是activity_custom_binding布局中ViewStub控件的ID在绑定类中生成的属性,其真实类名是androidx.databinding.ViewStubProxy,第二个viewStub才是布局中的ViewStub:
activityCustomBindingBinding.viewStub.viewStub
ViewStub布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<import type="com.im_hero.databinding.ConstantsKt"/>
<variable
name="viewStubData"
type="androidx.databinding.ObservableField<String>" />
</data>
<TextView
android:id="@+id/tvViewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{`ViewStub:`+viewStubData}"
android:visibility="@{ConstantsKt.INVISIBLE.equals(viewStubData) ? View.GONE : View.VISIBLE}" />
</layout>
如下是ViewStub的布局文件和常量定义:
// Constants.kt 文件中
const val INVISIBLE = "Invisible"
const val VISIBLE = "Visible""
下面是CustomBindingFragment的布局文件和实现代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data class="CustomDataBinding">
<import type="com.im_hero.databinding.ConstantsKt"/>
<variable
name="showViewStubStatus"
type="androidx.databinding.ObservableBoolean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CustomBindingFragment">
<ToggleButton
android:id="@+id/btnShowViewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="@{showViewStubStatus}"
android:textOn="@{ConstantsKt.VISIBLE}"
android:textOff="@{ConstantsKt.INVISIBLE}" />
</LinearLayout>
</layout>
其中 <data class=“CustomDataBinding”> 就是用来指定布局自动生成的绑定类名。
class CustomBindingFragment : Fragment(), CompoundButton.OnCheckedChangeListener{
lateinit var customDataBinding: CustomDataBinding
lateinit var customBindingFragmentListener: CustomBindingFragmentListener
val oBoolean = ObservableBoolean(false)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
customDataBinding = CustomDataBinding.inflate(inflater, container, false)
customDataBinding.showViewStubStatus = oBoolean
customDataBinding.btnShowViewStub.setOnCheckedChangeListener(this)
return customDataBinding.root
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is CustomBindingFragmentListener) {
customBindingFragmentListener = context
} else {
throw AndroidRuntimeException("Context must implements CustomBindingFragmentListener")
}
}
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
customBindingFragmentListener.showViewStub(isChecked)
}
interface CustomBindingFragmentListener {
fun showViewStub(checked: Boolean)
}
}
至此通过Fragment上的按钮控制Activity上的ViewStub的填充和显示隐藏的功能就完成了。这个例子主要是用于演示开头的那几个知识点,特别简单哈,主要是用于演示DataBinding可以给我们减少很多的关联代码。这样我们就主要关注与数据的更新和界面的逻辑,关联代码就完全交给了DataBinding。贴上运行结果图,ViweStub未显示的界面:
显示ViewStub的界面: