使用GridLayoutManager设置Paging Library的跨度大小

4
当使用 Paging Library 时,在 LoadStateLoading 时,将 GridLayoutManager 的 span 大小设置为 1。我尝试了这个解决方案,但它并没有起作用。
为了复制问题,请克隆官方存储库,并将 GridLayoutManager 设置在 SearchRepositoriesActivity 中。
我的代码在这里: MovieListFragment
....
private val adapter = MoviesAdapter()
....
private fun initAdapter() {
    val decoration = DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)
    binding.rvMovies.addItemDecoration(decoration)
    binding.rvMovies.layoutManager = GridLayoutManager(requireContext(), 2)
    binding.rvMovies.isNestedScrollingEnabled = true
    binding.rvMovies.adapter = adapter.withLoadStateFooter(
        footer = MoviesLoadStateAdapter { adapter.retry() }
    )
} 

电影适配器

class MoviesAdapter(
) : PagingDataAdapter<Movie, MoviesAdapter.ViewHolder>(MOVIE_COMPARATOR) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view = ItemMovieListBinding.inflate(LayoutInflater.from(parent.context))
    return ViewHolder(view)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val movie = getItem(position)
    if (movie != null) {
        val viewModel = MovieListItemViewModel(movie)
        holder.bind(viewModel)
    }
}

inner class ViewHolder(var viewBinding: ItemMovieListBinding) :
    RecyclerView.ViewHolder(viewBinding.root) {
    fun bind(viewModel: MovieListItemViewModel) {
        viewBinding.viewModel = viewModel

    }
}

companion object {
    private val MOVIE_COMPARATOR = object : DiffUtil.ItemCallback<Movie>() {
        override fun areItemsTheSame(oldItem: Movie, newItem: Movie): Boolean =
            oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: Movie, newItem: Movie): Boolean =
            oldItem == newItem
    }
}
}

电影加载状态适配器

class MoviesLoadStateAdapter(private val retry : () -> Unit) :
  LoadStateAdapter<MoviesLoadStateAdapter.MoviesLoadStateViewHolder>() 
{

override fun onBindViewHolder(holder: MoviesLoadStateViewHolder, loadState: LoadState) {
    holder.bind(loadState)
}

override fun onCreateViewHolder(
    parent: ViewGroup,
    loadState: LoadState
): MoviesLoadStateViewHolder {
    val view = LayoutInflater.from(parent.context)
        .inflate(R.layout.item_movie_load_state_footer_view, parent, false)
    val binding = ItemMovieLoadStateFooterViewBinding.bind(view)
    return MoviesLoadStateViewHolder(binding, retry)

}

inner class MoviesLoadStateViewHolder(private val binding: ItemMovieLoadStateFooterViewBinding,
retry : ()-> Unit) :
    RecyclerView.ViewHolder(binding.root) {
    init {
        binding.retryButton.setOnClickListener {
            retry.invoke()
        }
    }
    fun bind(loadState : LoadState){
        if(loadState is LoadState.Error){
            binding.errorMsg.text = loadState.error.localizedMessage
        }
        binding.progressBar.visibility  = toVisibility(loadState is LoadState.Loading)
    }
}
}

以下是翻译的结果:

这里的目标是让 ProgressBar 显示在屏幕中央。

enter image description here


请发布您的代码。 - Gabriele Mariotti
@GabrieleMariotti请查看更新的问题。 - Kishore Jethava
3个回答

10

我解决了它。这是我的代码

在你的Activity中

val gridLayoutManager = GridLayoutManager(activity, 2)
    gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
        override fun getSpanSize(position: Int): Int {
            val viewType = wallpaperAdapter.getItemViewType(position)
            return if(viewType == WALLPAPER_VIEW_TYPE) 1
            else 2
        }
    }

    binding.recyclerView.apply {
        this.layoutManager = gridLayoutManager
        this.setHasFixedSize(true)
        this.adapter = wallpaperAdapter
    }

在您的PagingDataAdapter中

override fun getItemViewType(position: Int): Int {
    if (position == itemCount){
        return NETWORK_VIEW_TYPE
    }else {
        return WALLPAPER_VIEW_TYPE
    }
}
希望它能为您工作。

2
如果我们到达分页列表的末尾,最后一个元素不会变成两个吗? - Dilpreet Singh

1
不要忘记
val concatAdapter = ConcatAdapter(**ConcatAdapter.Config.Builder().setIsolateViewTypes(false).build()**,adapter, empty, footer)

0

想分享一下,为了使上述解决方案起作用,您必须以这种方式构建您的连接适配器:

ConcatAdapter(ConcatAdapter.Config.Builder().setIsolateViewTypes(false).build())

文档中有解释:

 public static final class Config {
        /**
         * If {@code false}, {@link ConcatAdapter} assumes all assigned adapters share a global
         * view type pool such that they use the same view types to refer to the same
         * {@link ViewHolder}s.
         * <p>
         * Setting this to {@code false} will allow nested adapters to share {@link ViewHolder}s but
         * it also means these adapters should not have conflicting view types
         * ({@link Adapter#getItemViewType(int)}) such that two different adapters return the same
         * view type for different {@link ViewHolder}s.
         *
         * By default, it is set to {@code true} which means {@link ConcatAdapter} will isolate
         * view types across adapters, preventing them from using the same {@link ViewHolder}s.
         */
        public final boolean isolateViewTypes;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接