你好,最近我将我的项目从 java 切换到 kotlin,我是 kotlin 的初学者,我想在我的回收器 View 中实现分页
回收器 View 包含存储在 firebase 中的图像,这是我想要的
选项 1 是,首先在创建 fragment 时加载 20 个图像,当用户到达最后一个图像 (20) 时,它会在回收器 View 中加载接下来的 20 个图像
选项 2
(可选,但希望在我的应用程序中进行这种分页)
你见过 Pinterest 和 Instagram吗?如果你只是正常滚动,你可能看不到图像正在加载,直到你滚动得非常快,然后它会显示进度条?
例如:Pinterest
1:正常或慢速滚动Link
2:滚动速度非常快Link
如果可能的话我想要这种功能
我认为 Instagram 或 Pinterest 中正在发生的事情是为了例如
它们在开始时加载大约 20 个图像,当用户到达第 10 个图像时(还有 10 个图像等待用户查看),它们只加载接下来的 10 个图像,因此它只用 20 个图像维护适配器,而不是到达列表末尾以加载下一个图像(因此,如果用户滚动得非常快,这将是一个异常(exception))
Note: I just don't know what it is said pagination or something else and also not sure that what I said up are the technique used I'm just speculating
代码
Home_Fragment.kt
I only included the required code but if you want more references please tell me I will update the question btw the implemented pagination (don't know is it pagination or something else but it's not working)
val staggeredGridLayoutManager =
StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
postRecyclerView.layoutManager = staggeredGridLayoutManager
postRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
visibleItemCount = staggeredGridLayoutManager.childCount
totalItemCount = staggeredGridLayoutManager.itemCount
val firstVisibleItems: IntArray? = null
staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems)
if (loading) {
if (totalItemCount > previousTotal) {
loading = false
previousTotal = totalItemCount
}
}
if (!loading && totalItemCount - visibleItemCount
<= firstVisibleItem + visibleThreshold
) {
data
loading = true
}
}
})
data
// setupFirebaseAuth();
shimmerFrameLayout!!.startShimmer()
mUploads = ArrayList()
postsAdapter = PostAdapter_Home(requireContext(), mUploads)
postRecyclerView.adapter = postsAdapter
postRecyclerView.scrollToPosition(saved_position)
// postsAdapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY;
return view
}
private val data: Unit
get() {
databaseReference.addValueEventListener(object : ValueEventListener {
@SuppressLint("NotifyDataSetChanged")
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
shimmerFrameLayout!!.stopShimmer()
shimmerFrameLayout!!.visibility = View.GONE
postRecyclerView.visibility = View.VISIBLE
mUploads!!.clear()
for (dataSnapshot in snapshot.children) {
val upload = dataSnapshot.getValue(Upload::class.java)!!
upload.setmKey(dataSnapshot.key)
mUploads!!.add(upload)
}
}
postsAdapter!!.setUploads(mUploads)
//notify the adapter
postsAdapter!!.notifyItemRangeInserted(0, mUploads!!.size)
loading = true
}
override fun onCancelled(error: DatabaseError) {
loading = true
}
})
}
PostAdapter_Home.kt
class PostAdapter_Home(var mcontext: Context, var mUploads: MutableList<Upload?>?) :
RecyclerView.Adapter<PostAdapter_Home.PostViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
val view: View
view = LayoutInflater.from(mcontext)
.inflate(R.layout.post_item_container_home_ex, parent, false)
return PostViewHolder(view)
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
val shimmer = ColorHighlightBuilder()
.setBaseColor(Color.parseColor("#F3F3F3"))
.setBaseAlpha(1f)
.setHighlightColor(Color.parseColor("#E7E7E7"))
.setHighlightAlpha(1f)
.setDropoff(50f)
.build()
val shimmerDrawable = ShimmerDrawable()
shimmerDrawable.setShimmer(shimmer)
val uploadCurrent = mUploads?.get(position)
Glide.with(mcontext)
.load(uploadCurrent?.getmImageUrl())
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.placeholder(shimmerDrawable)
.fitCenter()
.into(holder.imageView)
}
override fun getItemCount(): Int {
return mUploads?.size!!
}
// public long getId() {
// return this.id;
// }
//
// @Override
// public long getItemId(int position) {
// return mUploads.get(position).Id;
// }
fun setUploads(uploads: MutableList<Upload?>?) {
mUploads = uploads
}
class PostViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ShapeableImageView
init {
imageView = itemView.findViewById(R.id.imagePostHome)
}
}
}
上传.kt
package com.example.myappnotfinal.AdaptersAndMore
import com.google.firebase.database.Exclude
class Upload {
private var mImageUrl: String? = null
private var mKey: String? = null
constructor() {}
constructor(imageUrl: String?) {
mImageUrl = imageUrl
}
fun getmImageUrl(): String? {
return mImageUrl
}
fun setmImageUrl(mImageUrl: String?) {
this.mImageUrl = mImageUrl
}
@Exclude
fun getmKey(): String? {
return mKey
}
@Exclude
fun setmKey(Key: String?) {
mKey = Key
}
}
最佳答案
最好将 Android 的分页库与用于 RV 的 PagingDataAdapter
结合使用,
您可以在线阅读优点和缺点,
它解决了您的问题
加载分页数据
由于它之前加载下一页,因此您不必担心滚动的慢速和快速
您需要创建一个 PagingSource 来加载数据
class PagingSource<T: BaseModel> (
private val endPoint : suspend (Int) -> ApiResult<PageResult<T?>>,
private val filters : suspend (T) -> Boolean = {true}
) : PagingSource<Int ,T>() {
companion object{
const val DEFAULT_STARTING_PAGE_INDEX = 0
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
Timber.d("load Called for : ${endPoint::class}")
val pageIndex = params.key ?: DEFAULT_STARTING_PAGE_INDEX
val responsePageable = endPoint(pageIndex)
val responseData : MutableList<T> = mutableListOf()
val nextKey: Int?
when( responsePageable ) {
is ApiResult.Success -> {
if(responsePageable.data.content.isNotEmpty()) {
nextKey = pageIndex + 1
responseData.addAll(responsePageable.data.content
.filterNotNull()
.filter { filters(it) }
)
}
else {
nextKey = null
}
}
is ApiResult.NetworkError -> {
return LoadResult.Error(
Throwable("No network connection!")
)
}
else -> {
nextKey = null
}
}
return LoadResult.Page(
data = responseData ,
prevKey = if(pageIndex == DEFAULT_STARTING_PAGE_INDEX) null else pageIndex ,
nextKey = nextKey
)
}
/**
* The refresh key is used for subsequent calls to PagingSource.Load after the initial load.
*/
override fun getRefreshKey(state: PagingState<Int, T>): Int? {
// We need to get the previous key (or next key if previous is null) of the page
// that was closest to the most recently accessed index.
// Anchor position is the most recently accessed index.
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}
上面是我的分页源码的自定义实现ref
它使用 ApiResult
作为响应包装器,您可以将其替换为 Response
(改进默认值)或 relevent API_RESULT files
这里是如何使用上面PagingSource
的示例
fun getCoreCharacters(
sortParam: Character.Companion.SortCharacter ,
filters: suspend (Character) -> Boolean
) : Flow<PagingData<Character>>{
return Pager(
config = PagingConfig(
pageSize = DEFAULT_PAGE_SIZE,
enablePlaceholders = false
),
pagingSourceFactory = {
PagingSource(endPoint = loadMore@{ x: Int ->
characterApi.getCoreCharacters(x ,sortParam.value)
},
filters = filters
)
}
).flow
}
关于android - 如何用kotlin实现分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70096562/