经过大量搜索,我知道使用常规适配器是可行的,但是我不知道如何使用Paging Library来实现。我不需要代码只是一个线索。
示例
答案 0 :(得分:8)
要添加分隔符,您实际上有2个选项:
对于分页库,仅选项2是可行的,因为它仅部分加载数据,并且插入分隔符变得更加复杂。您只需找出一种方法来检查项目x
与项目x-1
是否是不同的日期,并根据结果在视图中显示/隐藏日期部分。
答案 1 :(得分:2)
我和你在同一地点,我想出了这个解决方案。
不过,要注意这一点,为了实现这一点,我必须将日期转换器更改为数据库,从长到字符串以存储时间戳
这些是我的转换器
class DateConverter {
companion object {
@JvmStatic
val formatter = SimpleDateFormat("yyyyMMddHHmmss", Locale.ENGLISH)
@TypeConverter
@JvmStatic
fun toDate(text: String): Date = formatter.parse(text)
@TypeConverter
@JvmStatic
fun toText(date: Date): String = formatter.format(date)
}
}
虽然有一些开始信息,但我有一个我希望显示的报告标题列表,并可以进行分页并可以进行过滤
它们由此对象表示:
data class ReportHeaderEntity(
@ColumnInfo(name = "id") override val id: UUID
, @ColumnInfo(name = "name") override val name: String
, @ColumnInfo(name = "description") override val description: String
, @ColumnInfo(name = "created") override val date: Date)
我还想在列表中的项目之间添加分隔符,以按日期显示它们
我做到了以下几点:
我在这样的房间中创建了一个新查询
@Query(
"SELECT id, name, description,created " +
"FROM (SELECT id, name, description, created, created AS sort " +
" FROM reports " +
" WHERE :filter = '' " +
" OR name LIKE '%' || :filter || '%' " +
" OR description LIKE '%' || :filter || '%' " +
" UNION " +
" SELECT '00000000-0000-0000-0000-000000000000' as id, Substr(created, 0, 9) as name, '' as description, Substr(created, 0, 9) || '000000' AS created, Substr(created, 0, 9) || '256060' AS sort " +
" FROM reports " +
" WHERE :filter = '' " +
" OR name LIKE '%' || :filter || '%' " +
" OR description LIKE '%' || :filter || '%' " +
" GROUP BY Substr(created, 0, 9)) " +
"ORDER BY sort DESC ")
fun loadReportHeaders(filter: String = ""): DataSource.Factory<Int, ReportHeaderEntity>
这基本上为我过滤过的所有项目创建了分隔线
它还会创建一个用于排序的虚拟日期(时间为25:60:60,以便它始终显示在其他报告的前面)
然后我使用联合将其与我的列表合并,并按虚拟日期对其进行排序
我必须从长字符串更改为字符串的原因是因为在sql中使用字符串创建虚拟日期并将日期部分与整个日期时间分开要容易得多
上面创建了一个像这样的列表:
00000000-0000-0000-0000-000000000000 20190522 20190522000000
e3b8fbe5-b8ce-4353-b85d-8a1160f51bac name 16769 description 93396 20190522141926
6779fbea-f840-4859-a9a1-b34b7e6520be name 86082 description 21138 20190522141925
00000000-0000-0000-0000-000000000000 20190521 20190521000000
6efa201f-d618-4819-bae1-5a0e907ddcfb name 9702 description 84139 20190521103247
在我的PagedListAdapter中,我将其更改为PagedListAdapter<ReportHeader, RecyclerView.ViewHolder>
的实现(不是特定的查看器)
已添加到伴随对象:
companion object {
private val EMPTY_ID = UUID(0L,0L)
private const val LABEL = 0
private const val HEADER = 1
}
并覆盖获得如下视图类型:
override fun getItemViewType(position: Int): Int = if (getItem(position)?.id ?: EMPTY_ID == EMPTY_ID) LABEL else HEADER
然后我创建了两个单独的视图持有人:
class ReportHeaderViewHolder(val binding: ListItemReportBinding) : RecyclerView.ViewHolder(binding.root)
class ReportLabelViewHolder(val binding: ListItemReportLabelBinding) : RecyclerView.ViewHolder(binding.root)
并实现了其他类似的替代方法:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
HEADER -> ReportHeaderViewHolder(DataBindingUtil.inflate(inflater, R.layout.list_item_report, parent, false))
else -> ReportLabelViewHolder(DataBindingUtil.inflate(inflater, R.layout.list_item_report_label, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val reportItem = getItem(position)
when (getItemViewType(position)) {
HEADER -> {
(holder as ReportHeaderViewHolder).binding.apply {
report = reportItem
executePendingBindings()
}
}
LABEL -> {
(holder as ReportLabelViewHolder).binding.apply {
date = reportItem?.name
executePendingBindings()
}
}
}
}
我希望这有助于并激励人们找到更好的解决方案
答案 2 :(得分:1)
您可以使用 Paging 3 库中的insertSeparators
获得相同的结果。
确保您的商品在日期前为sorted
。
内部或viewmodel
检索Pager
之类的东西
private val communicationResult: Flow<PagingData<CommunicationHistoryItem>> = Pager(
PagingConfig(
pageSize = 50,
enablePlaceholders = false,
maxSize = 400,
initialLoadSize = 50
)
) {
CommunicationPagingSource(repository)
}.flow.cachedIn(viewModelScope)
毕竟insert separators
就像 标头
val groupedCommunicationResult = communicationResult
.map { pagingData -> pagingData.map { CommunicationHistoryModel.Body(it) } }
.map {
it.insertSeparators{ after, before ->
if (before == null) {
//the end of the list
return@insertSeparators null
}
val afterDateStr = after?.createdDate
val beforeDateStr = before.createdDate
if (afterDateStr == null || beforeDateStr == null)
return@insertSeparators null
val afterDate = DateUtil.parseAsCalendar(afterDateStr)?.cleanTime()?.time ?: 0
val beforeDate = DateUtil.parseAsCalendar(beforeDateStr)?.cleanTime()?.time ?: 0
if (afterDate > beforeDate) {
CommunicationHistoryModel.Header( DateUtil.format(Date(beforeDate))) // dd.MM.yyyy
} else {
// no separator
null
}
}
}
cleanTime
通过忽略时间grouping
需要 dd.MM.yyyy
fun Calendar.cleanTime(): Date {
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
return this.time
}
答案 3 :(得分:0)
如here所述,分页库可与PagedListAdapter一起使用。 PagedListAdapter是RecyclerView.Adapter的扩展,因此您可以像在Recyclerview(example)中那样简单地进行操作。仅用两个词-您需要为日期标题和内容项使用不同的视图类型。
答案 4 :(得分:0)
在绑定数据时,也需要在上一项中传递
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
val previousItem = if (position == 0) null else getItem(position - 1)
holder.bind(item, previousItem)
}
然后每个视图都设置一个标题,只有在上一项没有相同的标题时,该标题才可见。
val previousHeader = previousItem?.name?.capitalize().first()
val header = item?.name?.capitalize()?.first()
view.cachedContactHeader.text = header
view.cachedContactHeader.isVisible = previousHeader != header
答案 5 :(得分:0)
Kiskae's answer非常好,对于您的情况,选项2可能效果很好。
就我而言,我想再添加一个不在数据库中的项目,像这样:
它也必须是可点击的。覆盖getItemCount
的通常方法是返回+1并偏移其他方法的位置。
但是我偶然发现了另一种尚未见文献记载的方式,这在某些情况下可能有用。您可以使用union
将其他元素合并到查询中:
@Query("select '' as name, 0 as id " +
"union " +
"select name, id from user " +
"order by 1 asc")
DataSource.Factory<Integer, User> getAllDataSource();
这意味着数据源实际上在开始时就返回了另一个项目,因此无需调整位置。在适配器中,您可以检查该项目并以不同的方式处理它。
在您的情况下,查询必须有所不同,但我认为这是可能的。