问题描述
我想在我的Android应用中进行多项选择。 我以前做过,但是只能用ArrayAdapter。
我有一个Flow作为我的数据集,并且使用了带有ViewHolder的PagingDataAdapter。
我的问题是,如果数据集不仅是列表,而且我真的不能那么容易地访问它,该如何进行多重选择。
如果您想查找代码,请重新编码:
Fragment Adapter ViewHolder ViewModel
解决方法
我已经实现了一种自定义方式。
我在适配器中使用了一个可观察的列表,并将方法公开给视图持有者以选择他们自己。
我的代码:
class PhotoAdapter(
private val context: Context,private val photoRepository: PhotoRepository,private val viewPhotoCallback: KFunction1<Int,Unit>,val lifecycleOwner: LifecycleOwner
) : PagingDataAdapter<Photo,PhotoViewHolder>(differCallback) {
/**
* Holds the layout positions of the selected items.
*/
val selectedItems = ObservableArrayList<Int>()
/**
* Holds a Boolean indicating if multi selection is enabled. In a LiveData.
*/
var isMultiSelectMode: MutableLiveData<Boolean> = MutableLiveData(false)
var isEmpty: MutableLiveData<Boolean> = MutableLiveData(true)
override fun onBindViewHolder(holder: PhotoViewHolder,position: Int) {
holder.bindTo(this,getItem(position))
}
override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): PhotoViewHolder =
PhotoViewHolder(parent,context,photoRepository)
fun viewPhoto(position: Int) {
viewPhotoCallback.invoke(getItem(position)?.id!!)
}
fun disableSelection() {
selectedItems.clear()
isMultiSelectMode.postValue(false)
}
fun enableSelection() {
isMultiSelectMode.postValue(true)
}
fun addItemToSelection(position: Int): Boolean = selectedItems.add(position)
fun removeItemFromSelection(position: Int) = selectedItems.remove(position)
fun isItemSelected(position: Int) = selectedItems.contains(position)
fun isLastSelectedItem(position: Int) = isItemSelected(position) && selectedItems.size == 1
fun selectAll() {
for (i in 0 until itemCount) {
if (!isItemSelected(i)) {
addItemToSelection(i)
}
}
}
companion object {
/**
* Callback to check if items differ. Needed by [PagingDataAdapter].
*/
private val differCallback = object : DiffUtil.ItemCallback<Photo>() {
override fun areItemsTheSame(oldItem: Photo,newItem: Photo): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Photo,newItem: Photo): Boolean =
oldItem == newItem
}
}
}
class PhotoViewHolder(
parent: ViewGroup,private val context: Context,private val photoRepository: PhotoRepository
) : RecyclerView.ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.photo_item,parent,false)
) {
private val imageView: ImageView = itemView.findViewById(R.id.photoItemImageView)
private val checkBox: CheckBox = itemView.findViewById(R.id.photoItemCheckBox)
var photo: Photo? = null
private lateinit var adapter: PhotoAdapter
fun bindTo(adapter: PhotoAdapter,photo: Photo?) {
this.photo = photo
this.adapter = adapter
imageView.setOnClickListener {
if (adapter.isMultiSelectMode.value!!) {
// If the item clicked is the last selected item
if (adapter.isLastSelectedItem(layoutPosition)) {
adapter.disableSelection()
return@setOnClickListener
}
// Set checked if not already checked
setItemChecked(!adapter.isItemSelected(layoutPosition))
} else {
adapter.viewPhoto(layoutPosition)
}
}
imageView.setOnLongClickListener {
if (!adapter.isMultiSelectMode.value!!) {
adapter.enableSelection()
setItemChecked(true)
}
true
}
adapter.isMultiSelectMode.observe(adapter.lifecycleOwner,{
if (it) { // When selection gets enabled,show the checkbox
checkBox.visibility = View.VISIBLE
} else {
checkBox.visibility = View.GONE
}
})
adapter.selectedItems.addOnListChangedCallback(onSelectedItemsChanged)
listChanged()
loadThumbnail()
}
/**
* Listener for changes in selected images.
* Calls [listChanged] whatever happens.
*/
private val onSelectedItemsChanged =
object : ObservableList.OnListChangedCallback<ObservableList<Int>>() {
// No implementation needed
override fun onChanged(sender: ObservableList<Int>?) {
listChanged()
}
override fun onItemRangeChanged(
sender: ObservableList<Int>?,positionStart: Int,itemCount: Int
) {
listChanged()
}
override fun onItemRangeInserted(
sender: ObservableList<Int>?,itemCount: Int
) {
listChanged()
}
override fun onItemRangeMoved(
sender: ObservableList<Int>?,fromPosition: Int,toPosition: Int,itemCount: Int
) {
listChanged()
}
override fun onItemRangeRemoved(
sender: ObservableList<Int>?,itemCount: Int
) {
listChanged()
}
}
private fun listChanged() {
checkBox.isChecked = adapter.isItemSelected(layoutPosition)
}
private fun setItemChecked(checked: Boolean) {
layoutPosition.let {
if (checked) {
adapter.addItemToSelection(it)
} else {
adapter.removeItemFromSelection(it)
}
}
}