我做了一个View
,我想在许多页面上重复使用。它包含用户的反馈元素,例如ProgressBar
,TextView
等。
由于其中包含大量物品,因此将所有这些物品绑定在一起是这样的:
<layout ... >
<data>
<variable
name="screenObserver"
type="my.namespace.ScreenStateObserver" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout ... >
<my.namespace.view.ScreenStateView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:loading="@{screenObserver.isProgressVisible}"
app:errorText="@{screenObserver.errorTxt}"
app:buttonText="@{screenObserver.errorBtnTxt}"
app:errorVisible="@{screenObserver.isTextVisible}"
app:buttonVisible="@{screenObserver.isButtonVisible}"
app:onButtonClick="@{() -> screenObserver.onErrorResolve()}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我发现复制/粘贴整个XML块比较麻烦且容易出错。有什么办法可以简化这个过程?
ScreenStateObserver
只是我在ViewModel
中实现并按如下所示绑定的接口:
override fun onCreateView(...): View? {
val factory = InjectorUtils.provideViewModelFactory()
viewmodel = ViewModelProviders.of(this, factory).get(MyViewModel::class.java)
binding = MyFragmentBinding.inflate(inflater, container, false).apply {
screenObserver = viewmodel
}
}
class AtoZViewModel() : ViewModel(), ScreenStateObserver { ... }
interface ScreenStateObserver {
val isProgressVisible : MutableLiveData<Boolean>
val isTextVisible : MutableLiveData<Boolean>
val isButtonVisible : MutableLiveData<Boolean>
// [..]
}
谢谢!
答案 0 :(得分:0)
这是我减少代码的建议。
首先声明一个这样的类
interface ScreenState {
class Loading : ScreenState
class Error(val errorMessage: String, val errorButtonText: String) : ScreenState
}
在您的CustomView
里面
internal class ScreenStateView {
fun setState(state: ScreenState) {
if (state is ScreenState.Loading) {
// show loading
} else {
// hide loading
}
if (state is ScreenState.Error) {
//show {state.errorMessage} and {state.errorButtonText}
} else {
// hide error
}
}
}
在xml中使用
<my.namespace.view.ScreenStateView
...
app:state="@{screenObserver.screenState}"
...
app:onButtonClick="@{() -> screenObserver.onErrorResolve()}" /> // for onButtonClick I think it still better if we keep like this
希望有帮助
答案 1 :(得分:0)
我减少代码的解决方案是先为ScreenStateView定义类(此类中ScreenStateView的不同属性),然后根据需要使用它多次
答案 2 :(得分:-1)
您可以在数据绑定布局中使用<include>
。包含的布局文件可以具有自己的数据和变量,您也可以从主绑定类访问它们。
您必须创建一个布局文件(例如layout_state_view.xml
,其中包含您的视图和与视图相关的数据变量:
<layout>
<data>
<variable
name="screenObserver"
type="my.namespace.ScreenStateObserver" />
</data>
<my.namespace.view.ScreenStateView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:loading="@{screenObserver.isProgressVisible}"
app:errorText="@{screenObserver.errorTxt}"
app:buttonText="@{screenObserver.errorBtnTxt}"
app:errorVisible="@{screenObserver.isTextVisible}"
app:buttonVisible="@{screenObserver.isButtonVisible}"
app:onButtonClick="@{() -> screenObserver.onErrorResolve()}" />
</layout>
现在您可以在根布局文件中添加它:
<layout>
<data>
...
</data>
<LinearLayout //Can be any layout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout:="@layout/layout_state_view">
</LinearLayout>
</layout>
现在,当您使用绑定类时,如果您的根布局文件是R.layout.mainActivity,则它看起来像这样:
binding.layoutStateView.setScreenObserver(...)
您还可以在根目录布局中创建一个变量,然后使用文档上提到的bind
标签将该变量传递给子布局,但是由于您希望减少代码,因此这是不必要的。
注意:由于您只有一个视图,因此可能会想使用<merge>
标签。数据绑定的布局标签不支持merge
作为直接子级。
文档参考:
https://developer.android.com/topic/libraries/data-binding/expressions#includes