Skip to main content

How to implement a sticky header in a ListView in Kotlin Android

How to implement a sticky header in a ListView in Kotlin Android.

Here's a step-by-step tutorial on how to implement a sticky header in a ListView in Kotlin for Android.

Step 1: Create a new Android project

Start by creating a new Android project in your preferred IDE. Choose an appropriate project name and select the minimum SDK version that your app will support.

Step 2: Add the ListView to your layout file

Open the layout file for your main activity (activity_main.xml) and add a ListView element. Set its height and width to match_parent to fill the entire screen. Give it an id, for example, "listView".

<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Step 3: Create a layout file for the header

Create a new layout file called header_layout.xml. This layout will be used to define the appearance of the sticky header. Customize it as per your requirements. In this example, we'll use a simple TextView as the header.

<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/headerTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:padding="16dp"
android:background="@android:color/darker_gray"
android:textColor="@android:color/white"
android:text="Sticky Header" />

Step 4: Create a custom adapter

Create a new Kotlin class called CustomAdapter.kt. This class will extend the ArrayAdapter class and will be responsible for populating the ListView with data and displaying the sticky header.

class CustomAdapter(context: Context, objects: List<String>) :
ArrayAdapter<String>(context, 0, objects) {

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false)

// Set the data for each item in the ListView

return view
}

override fun getHeaderId(position: Int): Long {
// Return a unique identifier for each header
return getItem(position).subSequence(0, 1).hashCode().toLong()
}

override fun getHeaderView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.header_layout, parent, false)
val headerTextView = view.findViewById<TextView>(R.id.headerTextView)
headerTextView.text = getItem(position).subSequence(0, 1)

return view
}

override fun isItemViewTypePinned(viewType: Int): Boolean {
// Return true for the header view type
return viewType == 0
}

override fun getItemViewType(position: Int): Int {
// Return the view type for each item in the ListView
return if (isItemViewTypePinned(position)) 0 else 1
}
}

Step 5: Implement the sticky header behavior

Open your MainActivity.kt file and add the following code to set up the ListView with the sticky header behavior.

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val listView = findViewById<ListView>(R.id.listView)
val data = getListData() // Replace with your own data source

val adapter = CustomAdapter(this, data)
val pinnedHeaderListView = PinnedHeaderListViewWrapper(listView)
pinnedHeaderListView.adapter = adapter
}

private fun getListData(): List<String> {
// Return the data for the ListView
return listOf("Apple", "Banana", "Cherry", "Date", "Grape", "Lemon", "Mango", "Orange", "Pineapple", "Strawberry")
}
}

Step 6: Run the app

Run your app on an emulator or a physical device to see the sticky header implementation in action. You should be able to scroll through the ListView and observe the header staying at the top of the visible area.

That's it! You have successfully implemented a sticky header in a ListView using Kotlin for Android. You can customize the header layout and adapter as per your specific requirements.