3

我们的 App 中有这个功能,我们可以在其中上下拖动回收站视图项目。

在 ItemTouchHelper.Callback() 的 onMove() 中,我们调用

adapter.onItemMove(source.adapterPosition, target.adapterPosition)

适配器代码是这样的

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
    Collections.swap(dataList, fromPosition, toPosition)
    notifyItemMoved(fromPosition, toPosition)
    return true
}

现在,早期的适配器类正在扩展 RecyclerView.Adapter() 并且我们有以下方法来使用 DiffUtils 更新我们的列表

fun setDataList(feeds: List<User>): DiffUtil.DiffResult {
    val diffResult = DiffUtil.calculateDiff(ContentDiffCall(mFeeds, feeds))
    this.mFeeds.clear()
    this.mFeeds.addAll(feeds)
    return diffResult
}

拖放工作正常。

但是当我们从 ListAdapter 扩展我们的适配器类时,已经工作的功能(拖放)被破坏了。回收站视图中的第一个项目没有拖动到第二个项目之外,并且拖动的位置项目也没有得到更新。

恢复 ListAdapter 实现使其再次工作。

无法理解为什么当 ListAdapter 本身扩展 RecyclerView.Adapter 时这不起作用。

适配器类

class ContentListAdapter(
private val headerListener: HeaderClickListener?,
private val listener: ListItemClickListener?,
private val screen: Screen,
private val feedInteractor: FeedInteractionManager
) : ListAdapter<BaseUiModel, RecyclerView.ViewHolder>(ContentListDiffCall()), ContentTouchHelperAdapter {

private var dataList = ArrayList<BaseUiModel>()

init {
    setHasStableIds(true)
}

fun setDataList(data: List<BaseUiModel>) {
    dataList.clear()
    dataList.addAll(data)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
        HFType.CONTENT_LIST_HEADER.ordinal -> ContentListHeaderViewHolder.getInstance(
            parent,
            headerListener,
            R.layout.layout_content_list_header,
            screen
        )
        HFType.SONG.ordinal -> SongViewHolder.getInstance(parent, listener)
        else -> throw RuntimeException("there is no type that matches the type $viewType ; make sure your using types correctly")

    }
}

override fun getItemViewType(position: Int): Int {
    return getItem(position).hfType.ordinal
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val data = getItem(position)
    when (holder) {
        is SongViewHolder -> {
            if (data is SongUiModel) {
                holder.bindViews(data)
            }
        }
        is ContentListHeaderViewHolder -> {
            if (data is HeaderUiModel) {
                holder.bindViews(data)
            }
        }
    }
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>) {
    if (payloads.isEmpty()) {
        onBindViewHolder(holder, position)
        return
    }
    val data = getItem(position)
    when (holder) {
        is SongViewHolder -> {
            if (data is SongUiModel) {
                holder.bindViews(data, payloads)
            }
        }
        is ContentListHeaderViewHolder -> {
            if (data is HeaderUiModel) {
                holder.bindViews(data, payloads)
            }
        }
    }
}

override fun getItemId(position: Int): Long {
    val data = getItem(position)
    return data.hashCode().toLong()
}

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
    Collections.swap(dataList, fromPosition, toPosition)
    notifyItemMoved(fromPosition, toPosition)
    return true
}

override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
    super.onViewAttachedToWindow(holder)
    if (holder is HomeFeedViewHolder<*>) {
        holder.onHolderAttachedInViewPort()
    }
}

}

interface ContentTouchHelperAdapter {
      fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
}

片段内的代码片段

private fun setUpRecyclerView() {
    rv_item_list.apply {
        layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        recycledViewPool.setMaxRecycledViews(HFType.SONG.ordinal, 12)
     recycledViewPool.setMaxRecycledViews(HFType.CONTENT_LIST_HEADER.ordinal, 1)
    }

    val spaceItemDecorator = ContentListSpaceDecorator(25.dpToPx())
    rv_item_list.addItemDecoration(spaceItemDecorator)

    adapter = ContentListAdapter(this, this, this, screen, this)
    rv_item_list.adapter = adapter

    val callback = SimpleTouchListener(adapter, contentListViewModel)
    itemTouchHelper = ItemTouchHelper(callback)
    itemTouchHelper.attachToRecyclerView(rv_item_list)

  }

SimpleTouchListener 类

class SimpleTouchListener(
    private val listAdapter: ContentListAdapter,
    private val viewModel: ContentListViewModel
) :
    ItemTouchHelper.Callback() {
    private var fromPosition: Int? = null
    private var toPosition: Int? = null

    override fun isLongPressDragEnabled(): Boolean {
        return false
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return false
    }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        var dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
        if (viewHolder is ContentListHeaderViewHolder) {
            dragFlags = 0
        }
        return makeMovementFlags(dragFlags, 0)         
    }

    override fun onMove(
        recyclerView: RecyclerView,
        source: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        if (source.itemViewType != target.itemViewType) {
            return false
        }
        if (fromPosition == null) {
            fromPosition = source.adapterPosition
        }
        toPosition = target.adapterPosition
        listAdapter.onItemMove(source.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, i: Int) {
        // Notify the adapter of the dismissal
    }

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
            if (viewHolder is ItemTouchHelperViewHolder) {
                val itemViewHolder = viewHolder as ItemTouchHelperViewHolder?
                itemViewHolder?.onItemSelected()
            }
        }
        super.onSelectedChanged(viewHolder, actionState)
    }

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        if (viewHolder is ItemTouchHelperViewHolder) {
            // Tell the view holder it's time to restore the idle state
            val itemViewHolder = viewHolder as ItemTouchHelperViewHolder
            itemViewHolder.onItemClear()
        }
        if (fromPosition != null && toPosition != null) {
            //This method updates the list ordering in DB 
            viewModel.onContentPositionChange(fromPosition, toPosition)
        }
        fromPosition = null
        toPosition = null
    }
}

我们在成功时从观察者那里调用 setAdapterMethod

private fun setAdapterData(contentList: List<BaseUiModel>?) {
    contentList?.let { it ->
        adapter.setDataList(it)
        adapter.submitList(it)
    }
}
4

1 回答 1

2

ListAdaptersubmitList通过函数更新其内容:

/**
* Submits a new list to be diffed, and displayed.
* <p>
* If a list is already being displayed, a diff will be computed on a background thread, which
* will dispatch Adapter.notifyItem events on the main thread.
*
* @param list The new list to be displayed.
*/
public void submitList(@Nullable List<T> list) {
    mDiffer.submitList(list);
}

然后你可以打电话:

listAdapter.submitList(updatedList)
于 2019-11-27T09:04:21.503 回答