如何使用android数据绑定设置SwipeRefreshLayout刷新属性?
我正在使用android数据绑定库。 如果我想让视图可见,我可以这样写:如何使用android数据绑定设置SwipeRefreshLayout刷新属性?,android,data-binding,swiperefreshlayout,android-layout,Android,Data Binding,Swiperefreshlayout,Android Layout,我正在使用android数据绑定库。 如果我想让视图可见,我可以这样写: <TextView android:id="@+id/label_status" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:tex
<TextView
android:id="@+id/label_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{habitListViewModel.message}"
app:visibility="@{habitListViewModel.hasError ? View.VISIBLE : View.GONE}" />
<data>
<variable name="viewModel" type="ViewModel" />
</data>
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:refreshing="@{viewModel.isLoading}"
app:onRefreshListener="@{() -> viewModel.onRefresh()}">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
是否有一个选项可以以类似的(xml)方式绑定到swipeRefreshLayout的刷新属性
目前,我正在通过调用setRefreshing(true/false)在代码中对其进行设置,但希望在xml中使其保持一致 更新:
由于数据绑定从xml属性名称映射到set{AttributeName}
,您只需使用app:refreshing
,因为数据绑定将成功地将值提供给SwipeRefreshLayout
的setRefreshing
方法(我们很幸运,它是公共的):
...
//ListView,RecyclerView之类的
就这样!注意,您可以简单地使用
@{true}
或@{false}
而不是@{habitListViewModel.isLoading}
。希望有帮助。只需使用这个应用程序:刷新=“@{booleanValueHere}”
。数据绑定将自动检测回isRefreshing函数的引用。无需破解。关键是在中寻找公共方法。通常,数据绑定将查找没有集合的相应名称。例如,你会发现:
public class DiscoverMoviesViewModel extends ViewModel {
public MutableLiveData<Boolean> isLoading = new MutableLiveData<>(true);
.
.
.
public void refresh(){
isLoading.setValue(true);
//do your task
}
}
OnRefreshListener
由于OnRefreshListener是一个公共接口,只有一个方法,您可以在绑定中直接使用它,如下所示:
app:onRefreshListener="@{() -> viewModel.onRefresh()}"
更新状态
对于这一个,您使用另一个公共方法,它转换为:
app:refreshing="@{viewModel.isLoading}"
总之,它可以看起来像这样:
<TextView
android:id="@+id/label_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{habitListViewModel.message}"
app:visibility="@{habitListViewModel.hasError ? View.VISIBLE : View.GONE}" />
<data>
<variable name="viewModel" type="ViewModel" />
</data>
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:refreshing="@{viewModel.isLoading}"
app:onRefreshListener="@{() -> viewModel.onRefresh()}">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
viewmodel-java:
public class ViewModel implements DataProvider.Callback {
public ObservableBoolean isLoading = new ObservableBoolean();
private DataProvider provider;
MasterViewModel(@NonNull final DataProvider provider) {
this.provider = provider;
}
/* Needs to be public for Databinding */
public void onRefresh() {
isLoading.set(true);
provider.fetch(this);
}
public void onReady(List results){
isLoading.set(false);
}
public void onError(Exception oops){
isLoading.set(false);
Log.e("Stack", oops);
}
}
确保已将binding.viewModel
设置为片段/活动中的当前实例
这是我的案例中缺失的片段
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
FragmentDiscoverMoviesBinding binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_discover_movies, container, false);
viewModel = obtainViewModel(getActivity()); //get the viewmodel from the viewmodelFactory
binding.setViewModel(viewModel);
View rootView = binding.getRoot();
return rootView;
}
fragment_discover_movies.xml
<data>
<variable
name="viewModel"
type="com.ajdi.yassin.popularmovies.ui.movieslist.discover.DiscoverMoviesViewModel" />
</data>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:onRefreshListener="@{()-> viewModel.refresh()}"
app:refreshing="@{viewModel.isLoading}">
...
//ListView,RecyclerView or something
</android.support.v4.widget.SwipeRefreshLayout>
...
//ListView,RecyclerView之类的
然后在viewmodel中定义刷新函数
public class DiscoverMoviesViewModel extends ViewModel {
public MutableLiveData<Boolean> isLoading = new MutableLiveData<>(true);
.
.
.
public void refresh(){
isLoading.setValue(true);
//do your task
}
}
公共类DiscoverMoviesViewModel扩展了ViewModel{
public MutableLiveData isLoading=新的MutableLiveData(true);
.
.
.
公共无效刷新(){
isLoading.setValue(真);
//完成你的任务
}
}
很抱歉响应太晚……但是,当将app:refreshing值设置为true/false时,swipeRefreshLayout如何知道预期的行为?我不应该把它和一些行为联系起来吗?它将如何将app:refreshing属性与其设置刷新行为的内部刷新字段相连接?这就是为什么我称它为“一个小黑客”——这里的主要问题是Android数据绑定只是在绑定到对象属性时寻找对象的set{Name}
方法。这就是为什么我们调用自定义属性刷新。因此,当您绑定到它的某个值时,它将只查找setRefreshing
方法的SwipeRefreshLayout
对象,我们的对象正好包含该方法,因此行为将与您以编程方式调用setRefreshing(true/false)
的行为相同:)现在我明白了!斯马特:)谢谢你的解释!不客气:)这是一个不寻常的情况,因此解释是:)不需要attrs.xml,只需使用android:refreshing=“@{habitListViewModel.isLoading}”
这是您应该如何使用数据绑定库,并且应该是公认的答案。在我的情况下,应用程序:onRefreshListener不调用方法onRefresh。它只让微调器旋转,但不调用onRefresh。它对你有用吗?app:onRefreshListener仅设置侦听器。要真正开始刷新,需要触发事件。在这个示例中,我通过调用isLoading.set(true)
@enterco来完成,当我向下滑动以刷新时,永远不会调用onRefresh()。因此,使用您的示例,我的问题是,provider.fetch(this)
从未被调用。@user1795832您必须将“viewModel”设置为片段(或活动)中它的当前实例。@avlacatus是的,它会自动检测到它