Совместим ли SwipeRefreshLayout с адаптером с несколькими viewType? - PullRequest
0 голосов
/ 11 июня 2019

Я составляю список, который получит больше предметов, когда я попаду в конец списка.Я хочу, чтобы этот список тоже можно было обновлять, поэтому мне нужен SwipeRefreshLayout.

Допустим, у меня есть такой адаптер:

class OrdersListAdapter(val selected : (Order) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    fun addOrders(orders: ArrayList<Order>) {
        this.orders.addAll(orders)
        notifyItemRangeInserted(this.orders.size - orders.size + FIRST_ITEM_INDEX, orders.size)
    }

    fun setFirstOrders(orders: ArrayList<Order>) {
        this.orders = orders
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return (orders.size + 1 + FIRST_ITEM_INDEX)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            TYPE_ORDERS -> OrdersViewHolder(DataBindingUtil.inflate<OrdersItemBinding>(LayoutInflater.from(parent.context),
                R.layout.orders_item, parent, false).apply {
                viewModel = OrdersViewModel()
            })
            else -> LoadingMoreOrdersViewHolder(DataBindingUtil.inflate<LoadingMoreOrdersItemBinding>(LayoutInflater.from(parent.context),
                    R.layout.loading_more_orders_item, parent, false).apply {
                viewModel = LoadingMoreOrdersViewModel()
            })
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (getItemViewType(position)) {
            TYPE_ORDERS -> (holder as? OrdersViewHolder)?.setData(orders[position - FIRST_ITEM_INDEX])
            TYPE_LOADING -> (holder as? LoadingMoreOrdersViewHolder)?.setState(loading, error, noMoreItems)
        }
    }

    override fun getItemViewType(position: Int): Int =
            if (position == FIRST_ITEM_INDEX - 1) TYPE_HEADER else if (position == itemCount - 1) TYPE_LOADING else TYPE_ORDERS

Хорошо, если я поставлю свой RecyclerView какэто внутри SwipeRefreshLayout:

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/orders_rv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layoutManager="android.support.v7.widget.LinearLayoutManager" />

    </android.support.v4.widget.SwipeRefreshLayout>

Это отобразит все элементы, но refreshLayout не будет работать: если я вытащу свой взгляд, ничего не произойдет.

Но если я этого не сделаюустановите любой загрузочный макет внутри моего адаптера (тот, который находится внизу списка, чтобы загрузить больше элементов, накачанных с R.layout.loading_more_orders_item), тогда SwipeRefreshLayout будет работать правильно.

Как я могу иметь 2 типа просмотра в моемадаптер, И установить мой RecyclerView в SwipeRefreshLayout?

РЕДАКТИРОВАТЬ:

Вот мой onRefreshListener:

refreshLayout = binding.swipeRefreshLayout

refreshLayout?.setOnRefreshListener { reloadOrders() }

И в reloadOrders ():

private fun reloadOrders() {
    viewModel.setLoading()
    refreshLayout?.isRefreshing = false
    Observable.timer(1, TimeUnit.SECONDS)
            .subscribe { getOrders() }
}

Ответы [ 3 ]

1 голос
/ 11 июня 2019

Я полагаю, что то, что происходит, - это просмотрщик перехватывает события касания от swiperefreshlayout.Вы можете попробовать перезаписать linearlayout и его метод canScrollVertically(), чтобы вернуть false.Ура! * * 1002

0 голосов
/ 12 июня 2019

Хорошо, благодаря @ r2rek, я нашел решение, которое сработало для меня:

В коде мы создаем класс, который расширяет LinearLayoutManager и переопределяет метод canScrollVertically(), чтобы всегда возвращать false:

inner class MyLinearLayout(context: Context) : LinearLayoutManager(context) {
    override fun canScrollVertically(): Boolean {
        return (false)
    }
}

Затем, когда мы начинаем наш RecyclerView, мы применяем этот класс к нашему layoutManager:

ordersRv?.layoutManager = MyLinearLayout(this)

Это позволит вам обновить, но вы не сможете прокрутить свой RecyclerView (дух).
Чтобы это исправить, добавьте NestedScrollView в ваш xml, как показано ниже:

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/refresh_layout"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="8dp"
    android:visibility="@{viewModel.ordersVisibility}"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/toolbar">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/orders_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    </android.support.v4.widget.NestedScrollView>

</android.support.v4.widget.SwipeRefreshLayout>

Теперь вы можете прокрутить свой RecyclerView и нажать, чтобы обновить с помощью SwipeRefreshLayout.

Я думаю, что этот метод довольно хакерский, поэтому, если у кого-то есть лучшее решение, не стесняйтесь, сообщите нам!

0 голосов
/ 11 июня 2019

Отвечая на ваш вопрос, проблема совместимости не возникает. Не уверен в размере вашего макета, так как его высота 0dp. Я бы поиграл с размерами вида и иерархией вида.

...