Как установить свойство обновления 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 часть. Например, вы найдете там:

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 - спасибо за это) это сработало. Не уверен, почему, хотя.

Другие вопросы по тегам