删除 Android ViewPager2 中的项目
Delete Item in Android ViewPager2
我正在将我的代码从使用 androidx.viewpager
更新为 androidx.viewpager2
。我正在翻阅数量不确定的片段,这些片段显示从数据库中检索到的数据记录。加载视图寻呼机并通过我的数据进行分页效果很好,但我在删除项目和更新寻呼机适配器时遇到了一些麻烦。我想通过在我的适配器上调用 removeItem()
方法(参见下面的代码)来删除任何给定位置的项目。那应该从我的数据库中删除该项目以及我的片段,然后更新视图。
结果是从数据库中删除了正确的项目。但它不会从我的视图寻呼机中删除预期的片段,而是从下一页中删除。当前页面仍然可见。我有点将位置偏移正负 1 但没有成功 - 相反:在那些情况下,我的删除例程按最初预期执行。我也尝试了类似的考虑,例如.
我想实现以下行为:
- 删除任何项目时,应删除该页面并显示列表中的下一个。
- 删除列表中的 last/rightmost 项时,应删除该页面并显示上一页(现在是最后一页)。
- 删除最后一个剩余项目(none 剩余)时,activity 应该完成。
我的适配器代码:
internal class ShapePagerAdapter(private val activity: AppCompatActivity) : FragmentStateAdapter(activity) {
private val dbManager: DatabaseManager
private var shapeIds: MutableList<String>? = null
init {
dbManager = DatabaseManager(activity)
try {
shapeIds = dbManager.getShapeIds()
} catch (e: DatabaseAccessException) {
// ...
}
}
override fun getItemCount(): Int {
return if (null != shapeIds) shapeIds!!.size else 0
}
override fun createFragment(position: Int): Fragment {
return ShapeFragment.newInstance(shapeIds!![position])
}
fun removeItem(activity: AppCompatActivity, position: Int) {
try {
// Remove from Database.
dbManager.deleteShape(shapeIds!![position])
// Remove from View Pager.
shapeIds!!.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position , itemCount)
// Close if nothing to show anymore.
if (itemCount == 0) {
activity.finish()
}
} catch (e: DatabaseAccessException) {
// ...
}
}
}
对 FragmentStateAdapter
的进一步研究表明,在这种情况下必须重写它的两个方法:
containsItem(long itemId)
和 getItemId(int position)
Default implementation works for collections that don't add, move,
remove items.
通过搜索,我找到了 similar question 的答案,为我指明了正确的方向。它不会产生我问题中给出的确切行为,这就是为什么我要发布一个稍微改编的版本。
关键是这两种方法是在项目序列可能发生变化的情况下实施的。为了实现这一点,我维护了一个项目和项目 ID 的映射,并在序列发生变化时进行更新,在本例中是删除的项目。
internal class ShapePagerAdapter(private val activity: AppCompatActivity) : FragmentStateAdapter(activity) {
private val dbManager: DatabaseManager
private lateinit var shapeIds: MutableList<String>
private lateinit var itemIds: List<Long>
init {
dbManager = DatabaseManager(activity)
try {
shapeIds = dbManager.getShapeIds()
updateItemIds()
} catch (e: DatabaseAccessException) {
// ...
}
}
override fun getItemCount(): Int = shapeIds.size
override fun createFragment(position: Int): Fragment = ShapeFragment.newInstance(shapeIds[position])
fun removeItem(activity: AppCompatActivity, position: Int) {
try {
dbManager.deleteShape(shapeIds[position])
shapeIds.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position , itemCount)
updateItemIds()
if (itemCount == 0) activity.finish()
} catch (e: DatabaseAccessException) {
// ...
}
}
private fun updateItemIds() {
itemIds = shapeIds.map { it.hashCode().toLong() }
}
override fun getItemId(position: Int): Long = shapeIds[position].hashCode().toLong()
override fun containsItem(itemId: Long): Boolean = itemIds.contains(itemId)
}
}
我正在将我的代码从使用 androidx.viewpager
更新为 androidx.viewpager2
。我正在翻阅数量不确定的片段,这些片段显示从数据库中检索到的数据记录。加载视图寻呼机并通过我的数据进行分页效果很好,但我在删除项目和更新寻呼机适配器时遇到了一些麻烦。我想通过在我的适配器上调用 removeItem()
方法(参见下面的代码)来删除任何给定位置的项目。那应该从我的数据库中删除该项目以及我的片段,然后更新视图。
结果是从数据库中删除了正确的项目。但它不会从我的视图寻呼机中删除预期的片段,而是从下一页中删除。当前页面仍然可见。我有点将位置偏移正负 1 但没有成功 - 相反:在那些情况下,我的删除例程按最初预期执行。我也尝试了类似的考虑,例如
我想实现以下行为:
- 删除任何项目时,应删除该页面并显示列表中的下一个。
- 删除列表中的 last/rightmost 项时,应删除该页面并显示上一页(现在是最后一页)。
- 删除最后一个剩余项目(none 剩余)时,activity 应该完成。
我的适配器代码:
internal class ShapePagerAdapter(private val activity: AppCompatActivity) : FragmentStateAdapter(activity) {
private val dbManager: DatabaseManager
private var shapeIds: MutableList<String>? = null
init {
dbManager = DatabaseManager(activity)
try {
shapeIds = dbManager.getShapeIds()
} catch (e: DatabaseAccessException) {
// ...
}
}
override fun getItemCount(): Int {
return if (null != shapeIds) shapeIds!!.size else 0
}
override fun createFragment(position: Int): Fragment {
return ShapeFragment.newInstance(shapeIds!![position])
}
fun removeItem(activity: AppCompatActivity, position: Int) {
try {
// Remove from Database.
dbManager.deleteShape(shapeIds!![position])
// Remove from View Pager.
shapeIds!!.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position , itemCount)
// Close if nothing to show anymore.
if (itemCount == 0) {
activity.finish()
}
} catch (e: DatabaseAccessException) {
// ...
}
}
}
对 FragmentStateAdapter
的进一步研究表明,在这种情况下必须重写它的两个方法:
containsItem(long itemId)
和 getItemId(int position)
Default implementation works for collections that don't add, move, remove items.
通过搜索,我找到了 similar question 的答案,为我指明了正确的方向。它不会产生我问题中给出的确切行为,这就是为什么我要发布一个稍微改编的版本。
关键是这两种方法是在项目序列可能发生变化的情况下实施的。为了实现这一点,我维护了一个项目和项目 ID 的映射,并在序列发生变化时进行更新,在本例中是删除的项目。
internal class ShapePagerAdapter(private val activity: AppCompatActivity) : FragmentStateAdapter(activity) {
private val dbManager: DatabaseManager
private lateinit var shapeIds: MutableList<String>
private lateinit var itemIds: List<Long>
init {
dbManager = DatabaseManager(activity)
try {
shapeIds = dbManager.getShapeIds()
updateItemIds()
} catch (e: DatabaseAccessException) {
// ...
}
}
override fun getItemCount(): Int = shapeIds.size
override fun createFragment(position: Int): Fragment = ShapeFragment.newInstance(shapeIds[position])
fun removeItem(activity: AppCompatActivity, position: Int) {
try {
dbManager.deleteShape(shapeIds[position])
shapeIds.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position , itemCount)
updateItemIds()
if (itemCount == 0) activity.finish()
} catch (e: DatabaseAccessException) {
// ...
}
}
private fun updateItemIds() {
itemIds = shapeIds.map { it.hashCode().toLong() }
}
override fun getItemId(position: Int): Long = shapeIds[position].hashCode().toLong()
override fun containsItem(itemId: Long): Boolean = itemIds.contains(itemId)
}
}