Skip to content

Instantly share code, notes, and snippets.

@jpshelley
Last active July 21, 2019 12:02
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jpshelley/4e0d4aa16c20e91a6c01e48d278b4282 to your computer and use it in GitHub Desktop.
Save jpshelley/4e0d4aa16c20e91a6c01e48d278b4282 to your computer and use it in GitHub Desktop.
A Sectioned Adapter for Android via Kotlin
/**
* A section to use in Recycler Adapter's.
* It holds a sectioned position for use in determining the offset of the adapter items.
*/
data class AdapterSection(var firstPosition: Int, var title: String, var sectionedPosition: Int = 0)
/**
* An adapter that allows a RecyclerView to contain sections or subheaders
* much like the material docs describe.
* https://material.google.com/components/subheaders.html
*/
interface SectionedAdapter {
/**
* A list of sections to display in adapter.
*/
var sections: SparseArray<AdapterSection>
/**
* Returns true if the given position contains a section
*/
fun isSectionHeaderPosition(position: Int) = sections[position] != null
/**
* Determines the correct position based off of the number of currently displayed sections.
*/
fun sectionedPositionToPosition(sectionedPosition: Int): Int {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION
}
var offset = 0
for (i in 0..sections.size() - 1) {
if (sections.valueAt(i).sectionedPosition > sectionedPosition) {
break
}
--offset
}
return sectionedPosition + offset
}
fun positionToSectionedPosition(position: Int): Int {
var offset = 0
for (i in 0..sections.size() - 1) {
if (sections.valueAt(i).firstPosition > position) {
break
}
++offset
}
return position + offset
}
/**
* Clears the current set of selections and sets a new list.
* In order for the new sections to be displayed, one must first call
* notifyDatasetChanged()
*
* @param newSections The new sections to be set
*/
fun setSections(newSections: Array<AdapterSection>) {
sections.clear()
val sortedSections = newSections.clone()
Arrays.sort<AdapterSection>(sortedSections) { o, o1 ->
when {
o.firstPosition == o1.firstPosition -> 0
o.firstPosition < o1.firstPosition -> -1
else -> 1
}
}
var offset = 0 // offset positions for the headers we're adding
sortedSections.forEach {
it.sectionedPosition = it.firstPosition + offset
sections.append(it.sectionedPosition, it)
++offset
}
}
/**
* Returns the nearest section header if one exists
*/
tailrec fun getNearestSectionHeader(sectionedPosition: Int): Int {
if (isSectionHeaderPosition(sectionedPosition)) {
return sectionedPosition
} else {
return getNearestSectionHeader(sectionedPosition - 1)
}
}
}
@m-glebova
Copy link

m-glebova commented Feb 25, 2019

Could you please share how you use it with delegates approach?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment