How to add date separators in recycler view using Paging Library?

前端 未结 6 1415
感动是毒
感动是毒 2021-02-05 10:34

After a lot of searching, I know its possible with regular adapter, but I have no idea how to do it using Paging Library. I don`t need code just a clue.

Example

6条回答
  •  借酒劲吻你
    2021-02-05 11:02

    I was in the same spot as you and I came up with this solution.

    One important note though, in order to implement this I had to change my date converter to the database, from long to string to store a timestamp

    these are my converters

    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)
        }
    }
    

    Some starting info though, I have a list of report headers that I wish to show , and page through and be able to filter

    They are represented by this object:

    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)
    

    I also wanted to add separators between the items in the list to show them by date

    I achieved this by doing the following:

    I created a new query in room like this

     @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
    

    This basically creates a separator line for all the items I have filtered through

    it also creates a dummy date for sorting (with the time of 25:60:60 so that it will always appear in front of the other reports)

    I then combine this with my list using union and sort them by the dummy date

    The reason I had to change from long to string is because it is much easier to create dummy dates with string in sql and seperate the date part from the whole date time

    The above creates a list like this:

    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
    

    In my PagedListAdapter I changed it to be an implementation of PagedListAdapter (not a specific viewholder)

    Added to the companion object:

    companion object {
        private val EMPTY_ID = UUID(0L,0L)
        private const val LABEL = 0
        private const val HEADER = 1
    }
    

    and overrode get view type like so:

    override fun getItemViewType(position: Int): Int = if (getItem(position)?.id ?: EMPTY_ID == EMPTY_ID) LABEL else HEADER
    

    I then created two seperate view holders :

    class ReportHeaderViewHolder(val binding: ListItemReportBinding) : RecyclerView.ViewHolder(binding.root) 
    
    class ReportLabelViewHolder(val binding: ListItemReportLabelBinding) : RecyclerView.ViewHolder(binding.root)
    

    and implemented the other overriden methods like so:

    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()
                }
            }
        }
    }
    

    I hope this helps and inspires people to find even better solutions

提交回复
热议问题