Android RecyclerView Photo Grid Group by Date Header
September 26, 2019I wanted to create the following layout.
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 columns
val layoutManager = GridLayoutManager(context, 3)
list.layoutManager = layoutManager
// assign adapter
adapter = LocalAdapter()
list.adapter = adapter
// expand 3 columns to single row to show date
layoutManager.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>()
// date
items.add(ViewItem.DateItem(posted = posted))
// photos
items.add(ViewItem.ImageItem(
created = created,
uri = Uri.fromFile(File(filepath))
))
...
// date
...
// photos
...
// load items into adapter
adapter.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
}
- android
- android-ktx
- android-studio
- apps-script
- bootstrap
- cloud-functions
- coding-interview
- coroutines
- crashlytics
- css
- dagger2
- datastore
- datetime
- eslint
- firebase
- firebase-auth
- firestore
- firestore-security-rules
- flask
- fontawesome
- fresco
- git
- github
- glide
- google-app-engine
- google-cloud-storage
- google-drive
- google-maps
- google-places
- google-play
- google-sheets
- gradle
- html
- hugo
- inkscape
- java
- java-time
- javascript
- kotlin
- layout
- lets-encrypt
- lifecycle
- linux
- logging
- markdown
- md5
- moshi
- navigation
- nginx
- nodejs
- npm
- payment
- pip
- python
- recylerview
- regex
- room
- rxjava
- selenium
- social-media
- ssh
- ssl
- static-site-generator
- sublime-text
- ubuntu
- unit-test
- uwsgi
- viewmodel
- viewpager2
- virtualbox
- vue-cli
- vuejs
- vuepress
- web-development
- web-hosting
- webpack
- windows
- workmanager
- yarn