Android RecyclerView Photo Grid Group by Date Header

I wanted to create the following layout.

Android Photo Grid with Header

Layout

Main Layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

Layout for Photo (home_item_image.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/draweeView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        fresco:placeholderImage="@drawable/img_placeholder_100dp"
        fresco:viewAspectRatio="1"
        />
</FrameLayout>

NOTE: Using Fresco for image loading.

Layout for date header (home_item_date.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:padding="16dp"
        android:id="@+id/dateTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</FrameLayout>

RecyclerView

Activty/Fragment class variable

private lateinit var adapter: LocalAdapter

Class for RecyclerView object

sealed class ViewItem(val resource: Int) {    class DateItem(val posted: LocalDateTime): ViewItem(R.layout.home_item_date)    class ImageItem(val created: LocalDateTime, val uri: Uri): ViewItem(R.layout.home_item_image)}

Setup RecyclerView

// use GridLayout with 3 columnsval layoutManager = GridLayoutManager(context, 3)list.layoutManager = layoutManager// assign adapteradapter = LocalAdapter()list.adapter = adapter// expand 3 columns to single row to show datelayoutManager.spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {    override fun getSpanSize(position: Int): Int {        return when (adapter.getItemViewType(position)) {            R.layout.home_item_date -> 3            else -> 1        }    }}

Load Data

val items = mutableListOf<ViewItem>()// dateitems.add(ViewItem.DateItem(posted = posted))// photositems.add(ViewItem.ImageItem(    created = created,    uri = Uri.fromFile(File(filepath))))...// date...// photos...// load items into adapteradapter.replaceItems(items)

Adapter

class LocalAdapter : RecyclerView.Adapter<LocalAdapter.ViewHolder>() {    private var items = listOf<ViewItem>()    override fun getItemViewType(position: Int): Int {        return items[position].resource    }    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {        val view = LayoutInflater.from(parent.context)            .inflate(viewType, parent, false)        return ViewHolder(view)    }    override fun onBindViewHolder(holder: ViewHolder, position: Int) {        when(val item = items[position]) {            is ViewItem.DateItem -> {                val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)                holder.dateTextView.text = item.posted.format(formatter)            }            is ViewItem.ImageItem -> {                holder.draweeView.setImageURI(item.uri)            }        }    }    fun replaceItems(items: List<ViewItem>) {        this.items = items        notifyDataSetChanged()    }    override fun getItemCount(): Int {        return items.size    }    inner class ViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),        LayoutContainer}

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.