由于嵌套滚动问题,我不得不将带有过滤器功能的 ArrayAdapter
重新制作为 RecyclerView Adapter
。但是在我重新制作后,RecyclerView
为空,但 adapter.itemCount
返回正确的值。问题是在我调用 adapter.notifyDataSetChanged()
后,它没有调用 onCreateViewHolder
或 onBindViewHolder
函数。
class ZoneViewHolder(val root: ViewGroup): RecyclerView.ViewHolder(root) {
fun bind(
zone: FlightZone,
manageZoneCheck: (View)-> Unit,
maybeAutoselectZone: (View) -> Unit){
root.setOnClickListener {
manageZoneCheck(root.find(R.id.check))
}
root.find<View>(R.id.check).also { check->
check.setOnClickListener {
manageZoneCheck(check)
}
//autoselect zone if it was previously picked (after search reset)
maybeAutoselectZone(check)
}
root.findText(R.id.zoneNum).text = zone.name
root.findText(R.id.zoneName).apply {
isSelected = true
text = zone.radarInfo
}
root.findText(R.id.separator).setVisibleNotGone(zone.radarInfo != null)
}
}
class ZoneListAdapter(
private val ctx: Context,
private val inflater: LayoutInflater,
private val zoneView: Int,
private val zoneList: List<FlightZone>,
private var list: MutableList<FlightZone>,
private val pickedZones: List<FlightZone>,
private val onZoneChecked: (FlightZone, Boolean) -> Unit,
private val onAllZonesChecked: (Boolean) -> Unit,
private val onFilterDone: (List<FlightZone>) -> Unit
): RecyclerView.Adapter<ZoneViewHolder>(), Filterable{
override fun getItemCount() = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
return ZoneViewHolder(inflater.inflate(zoneView, parent, false) as ViewGroup)
}
override fun onBindViewHolder(vh: ZoneViewHolder, position: Int) {
val zone = list[position]
App.log("ZoneListAdapter: onBindView: ${list.size}")
vh.bind(
zone,
manageZoneCheck = { check->
manageZoneCheck(check, zone)
},
maybeAutoselectZone = {check->
App.log("ZoneListAdapter: alreadyPicked: ${pickedZones.size}")
if (pickedZones.find { it.id == zone.id } != null) check.callOnClick()
}
)
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
data class ZoneFilterable(val zone: FlightZone, val prefixLength: Int)
internal var tempItems: MutableList<FlightZone> = zoneList.toMutableList()
internal var suggestions: MutableList<ZoneFilterable> = mutableListOf()
internal val sharedCounterLock = Semaphore(1)
private var filter = object : Filter(){
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
sharedCounterLock.acquire()
suggestions.clear()
filterByName(constraint)
suggestions.sortedByDescending { it.prefixLength }
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
sharedCounterLock.release()
filterResults
} else {
FilterResults()
}
}
private fun filterByName(constraint: CharSequence?){
tempItems.forEach {
val zoneName = it.name.toLowerCase(Locale.getDefault())
val zoneNameNonAccent = zoneName.removeDiacritics()
val query = constraint.toString().toLowerCase(Locale.getDefault())
val queryNonAccent = query.removeDiacritics()
App.log("FlightZonePicker filter zone name non-accent: $zoneNameNonAccent")
if (zoneNameNonAccent.contains(queryNonAccent)) {
val prefix = zoneName.commonPrefixWith(query)
suggestions.add(ZoneFilterable(it, prefix.length))
}
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
if (results.count > 0) {
list.clear()
val filterList = results.values as? List<Any?>
var resultList = mutableListOf<FlightZone>()
GlobalScope.launch(Dispatchers.Main) {
val resultListAsync = async {
withContext(Dispatchers.Default) {
val list = mutableListOf<FlightZone>()
sharedCounterLock.acquire()
val iter = filterList?.iterator()
iter?.let {
while (iter.hasNext()) {
val item = iter.next()
(item as ZoneFilterable).let { (zoneEntity) -> list.add(zoneEntity) }
}
}
sharedCounterLock.release()
return@withContext list
}
}
resultList = resultListAsync.await().take(10).toMutableList()
App.log("ZoneListAdapter: Results: ${resultList.size}")
list.addAll(resultList)
onFilterDone.invoke(resultList)
}
}
}
}
init {
tempItems = zoneList.toMutableList()
}
override fun getFilter(): Filter {
return filter
}
}
MainClass:
zoneListRecycleView = findViewById(R.id.zoneResults)
zoneListAdapter = ZoneListAdapter(
ctx,
f.layoutInflater,
R.layout.zone_pick_item,
zoneList,
filteredZones,
pickedZones,
onZoneChecked = {
zone, isPicked ->
pickedZones.apply {
if (isPicked){
if (find { it.id == zone.id } == null) add(zone)
} else {
if (find { it.id == zone.id } != null) remove(zone)
}
}
zoneListAdapter.notifyDataSetChanged()
},
onAllZonesChecked = {ischecked->
pickedZones.apply {
clear()
if(ischecked) addAll(zoneList)
}
zoneListAdapter.notifyDataSetChanged()
},
::onFilterResult
)
zoneListRecycleView.adapter = zoneListAdapter
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.notifyDataSetChanged()
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
更新:
我将 Adapter
更改为 ListAdapter
并将 publishResults
函数更改为
resultList = resultListAsync.await().take(10).toMutableList()
onFilterDone.invoke(resultList)
在我的父类中,我调用:
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.submitList(filteredZones)
App.log("ZonelistAdapter: filteredList = ${filteredZones.size}")
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
日志:
app: ZonelistAdapter: filteredList = 10
app: ZonelistAdapter: count = 0
适配器仍有一些问题。因此过滤器功能按预期工作,但适配器和回收站视图由于某种原因没有显示项目。