Как установить свойство обновления SwipeRefreshLayout с помощью привязки данных Android?
Я использую библиотеку привязки данных Android. Если я хочу сделать видимость видимой, я могу написать что-то вроде этого:
<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}" />
Есть ли возможность связать со свойством обновления swipeRefreshLayout аналогичным (xml) способом?
В настоящее время я устанавливаю его в коде, вызывая setRefreshing(true/false), но хотел бы, чтобы в xml он был согласованным.
5 ответов
ОБНОВЛЕНО: поскольку привязка данных сопоставляется с именем атрибута xml set{AttributeName}
Вы можете просто использовать app:refreshing
, поскольку привязка данных успешно предоставит значение setRefreshing
метод SwipeRefreshLayout
(который к счастью для нас существует и является публичным):
<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:refreshing="@{habitListViewModel.isLoading}">
...
//ListView,RecyclerView or something
</android.support.v4.widget.SwipeRefreshLayout>
Это оно! Обратите внимание, что вы можете просто использовать @{true}
или же @{false}
вместо @{habitListViewModel.isLoading}
, Надеюсь, это поможет.
Не надо взламывать. Ключ заключается в поиске открытых методов в документации SwipeRefreshLayout. В общем случае Databinding будет искать соответствующее имя без set
часть. Например, вы найдете там:
- setOnRefreshListener (слушатель SwipeRefreshLayout.OnRefreshListener)
- setRefreshing (логическое обновление)
OnRefreshListener
Поскольку OnRefreshListener является общедоступным интерфейсом с одним методом, вы можете напрямую использовать это в привязке, например:
app:onRefreshListener="@{() -> viewModel.onRefresh()}"
Обновление статуса
Для этого вы используете другой публичный метод, который переводится в:
app:refreshing="@{viewModel.isLoading}"
Все вместе это может выглядеть примерно так:
<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:
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
к его текущему экземпляру в вашем фрагменте / Activity.
Вот чего не хватало в моем случае во фрагменте.
@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>
А затем в вашей модели просмотра определите функцию обновления.
public class DiscoverMoviesViewModel extends ViewModel {
public MutableLiveData<Boolean> isLoading = new MutableLiveData<>(true);
.
.
.
public void refresh(){
isLoading.setValue(true);
//do your task
}
}
Просто используйте это app:refreshing="@{booleanValueHere}"
, Привязка данных автоматически обнаружит ссылку на функцию isRefreshing.
У меня недостаточно репутации, чтобы комментировать, поэтому я дополню ответы здесь.
@Entreco прав, нет необходимости использовать attrs.xml.
Я просто хочу указать, что это не работает для меня, потому что мой ViewModel имел свойство ObservableField<Boolean>
,
Когда я изменил это на ObservableBoolean
(как в примере с Entreco - спасибо за это) это сработало. Не уверен, почему, хотя.