XML 数据绑定过多
Too many XML data bindings
我制作了一个 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>
我发现 copy/pasting 整个 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>
// [..]
}
谢谢!
这是我减少代码的建议。
首先像这样声明一个class
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
希望对您有所帮助
您可以在数据绑定布局中使用 <include>
。包含的布局文件可以有自己的数据和变量,您也可以从主绑定访问这些数据和变量 class。
您必须创建一个布局文件(例如 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>
现在当你使用绑定 class 时,如果你的根布局文件是 R.layout.mainActivity 那么它看起来像这样:
binding.layoutStateView.setScreenObserver(...)
您还可以在根布局中创建一个变量,然后使用文档中提到的 bind
标记将该变量传递给子布局,但由于您希望减少代码,因此没有必要这样做。
注意:由于您只有一个视图,您可能会想使用 <merge>
标签。数据绑定的布局标签不支持 merge
作为直接子标签。
Documentation Reference:
https://developer.android.com/topic/libraries/data-binding/expressions#includes
我减少代码的解决方案是首先为 ScreenStateView 定义 class(此 class 中 ScreenStateView 的不同属性)然后根据需要多次使用它
我制作了一个 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>
我发现 copy/pasting 整个 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>
// [..]
}
谢谢!
这是我减少代码的建议。
首先像这样声明一个class
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
希望对您有所帮助
您可以在数据绑定布局中使用 <include>
。包含的布局文件可以有自己的数据和变量,您也可以从主绑定访问这些数据和变量 class。
您必须创建一个布局文件(例如 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>
现在当你使用绑定 class 时,如果你的根布局文件是 R.layout.mainActivity 那么它看起来像这样:
binding.layoutStateView.setScreenObserver(...)
您还可以在根布局中创建一个变量,然后使用文档中提到的 bind
标记将该变量传递给子布局,但由于您希望减少代码,因此没有必要这样做。
注意:由于您只有一个视图,您可能会想使用 <merge>
标签。数据绑定的布局标签不支持 merge
作为直接子标签。
Documentation Reference:
https://developer.android.com/topic/libraries/data-binding/expressions#includes
我减少代码的解决方案是首先为 ScreenStateView 定义 class(此 class 中 ScreenStateView 的不同属性)然后根据需要多次使用它