使用 GridLayoutManager 在分页库中设置跨度大小
Set span size in Paging Library with GridLayoutManager
当分页库中 LoadState
为 Loading
时,在 GridLayoutManager
中将跨度大小设置为 1。
我已尝试 this 解决方案,但它不起作用。
对于复制问题:克隆 this 官方仓库并在 SearchRepositoriesActivity
中设置 GridLayoutManager
我的代码在这里
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
}
}
}
MoviesLoadStateAdapter
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
应该显示在屏幕中央。
我解决了。这是我的代码
在你的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
}
}
希望对你有用。
别忘了
val concatAdapter = ConcatAdapter(**ConcatAdapter.Config.Builder().setIsolateViewTypes(false).build()**,adapter, empty, footer)
只是想分享一下,为了使上述解决方案有效,您必须以这种方式构建您的 concat 适配器:
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;
当分页库中 LoadState
为 Loading
时,在 GridLayoutManager
中将跨度大小设置为 1。
我已尝试 this 解决方案,但它不起作用。
对于复制问题:克隆 this 官方仓库并在 SearchRepositoriesActivity
GridLayoutManager
我的代码在这里
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
}
}
}
MoviesLoadStateAdapter
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
应该显示在屏幕中央。
我解决了。这是我的代码
在你的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
}
}
希望对你有用。
别忘了
val concatAdapter = ConcatAdapter(**ConcatAdapter.Config.Builder().setIsolateViewTypes(false).build()**,adapter, empty, footer)
只是想分享一下,为了使上述解决方案有效,您必须以这种方式构建您的 concat 适配器:
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;