Compose vertical list LazyColumn

Basic list one

Use items to load data in the LazyColumn component, and rememberLazyListState() combined with rememberCoroutineScope() returns to the top.

/**
 *Basic list one
 */
@Composable
funItems() {
    Box(modifier = Modifier.fillMaxSize()) {
        val context = LocalContext.current
        val dataList = arrayListOf<Int>()
        for (index in 1..50) {
            dataList.add(index)
        }

        val listState = rememberLazyListState()
        LazyColumn(state = listState) {
            items(dataList) { data ->
                Text(
                    text = "No. ${data} data",
                    textAlign = TextAlign.Center,
                    //The running effect will be different if the order of property setting is different.
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 1.dp)
                        .background(Color.White)
                        .clickable {
                            Toast
                                .makeText(context, "$data", Toast.LENGTH_SHORT)
                                .show()
                        }
                        .padding(10.dp)
                )
            }
        }

        //Back to top
        val coroutineScope = rememberCoroutineScope()
        Image(
            modifier = Modifier
                .padding(end = 10.dp, bottom = 10.dp)
                .width(45.dp)
                .height(45.dp)
                .clip(CircleShape)
                .align(Alignment.BottomEnd)
                .background(Color.Blue)
                .clickable {
                    coroutineScope.launch {
                        listState.animateScrollToItem(index = 0)
                    }
                },
            painter = painterResource(id = R.drawable.top),
            contentDescription = "Back to top icon"
        )
    }
}

Basic List 2

Data is loaded in LazyColumn through the itemsIndexed attribute.

/**
 *Basic list two
 */
@Composable
fun ItemsIndexed() {
    val context = LocalContext.current
    val stringList = arrayListOf<String>()
    for (index in 1..50) {
        stringList.add(index.toString())
    }
    LazyColumn {
        //stringList.toArray() method can convert List to Array through List's toArray method
        itemsIndexed(stringList) { index, data ->
            Text(
                text = "My index is: ${index}, my data is: $data",
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 1.dp)
                    .background(Color.White)
                    .clickable {
                        Toast
                            .makeText(context, data, Toast.LENGTH_SHORT)
                            .show()
                    }
            )
        }
    }
}

Multiple Type List

Load different layouts based on different data types.

/**
 *Multiple Type list
 */
@Composable
fun AnyTypeList() {
    val charList = arrayListOf<Chat>()
    charList.apply {
        add(Chat("Hello"))
        add(Chat("What are you doing"))
        add(Chat("I want to ask you something"))
        add(Chat("Nothing done, still writing code!", false))
        add(Chat("What's the matter, brother?", false))
        add(Chat("It's okay..."))
        add(Chat("Okay...", false))
    }

    LazyColumn {
        items(charList) { data ->
            if (data.isLeft) {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 10.dp)
                ) {
                    //Interval setting
                    Spacer(modifier = Modifier.height(10.dp))
                    Row(
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Image(
                            modifier = Modifier
                                .width(35.dp)
                                .height(35.dp)
                                //Cut the circle
                                .clip(CircleShape),
                            painter = painterResource(id = R.drawable.ic_launcher_background),
                            contentDescription = "Left avatar"
                        )
                        Spacer(modifier = Modifier.width(10.dp))
                        Text(
                            data.content,
                            modifier = Modifier
                                .wrapContentWidth()
                                .background(Color.Yellow)
                                .padding(10.dp),
                        )
                    }
                }
            } else {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(end = 10.dp),
                    horizontalAlignment = Alignment.End
                ) {
                    Spacer(modifier = Modifier.height(10.dp))
                    Row(
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Text(
                            data.content,
                            modifier = Modifier
                                .wrapContentWidth()
                                .background(Color.Green)
                                .padding(10.dp)
                        )
                        Spacer(modifier = Modifier.width(10.dp))
                        Image(
                            modifier = Modifier
                                .width(35.dp)
                                .height(35.dp)
                                .clip(CircleShape),
                            painter = painterResource(id = R.drawable.ic_launcher_background),
                            contentDescription = "right avatar"
                        )
                    }
                }
            }
        }
    }
}

Data class:

/**
 * created by cwj on 2023-10-16
 * Description: Multi-type list class
 */
data class Chat(val content: String, val isLeft: Boolean = true)

Sticky title list

Use sticky header stickyHeader component. When the list slides, the first-level title is suspended at the top. As the list slides and the first-level list slides out and is replaced, a first-level title remains suspended at the top.

/**
 * Sticky title list
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun StickyHeaderTest() {
    val context = LocalContext.current
    val letters = arrayListOf("Type One", "Type Two", "Type Three", "Type Four", "Type Five")
    val contactList = arrayListOf<Contact>()
    val nameList = arrayListOf<String>()
    for (index in 1..5) {
        nameList.add("subitem$index")
    }
    for (index in letters.iterator()) {
        contactList.add(Contact(letters = index, nameList))
    }

    LazyColumn {
        contactList.forEach { (letter, nameList) ->
            stickyHeader {
                Text(
                    text = letter,
                    modifier = Modifier
                        .background(Color.LightGray)
                        .padding(start = 10.dp)
                        .fillMaxWidth(),
                    fontSize = 25.sp
                )
            }

            items(nameList) { contact ->
                Text(
                    text = contact,
                    modifier = Modifier
                        .padding(10.dp)
                        .background(Color.White)
                        .fillMaxWidth()
                        .clickable {
                            Toast
                                .makeText(context, contact, Toast.LENGTH_SHORT)
                                .show()
                        },
                    textAlign = TextAlign.Center,
                    fontSize = 25.sp
                )
            }
        }
    }
}

Data classes that can correspond to sticky titles and list data:

/**
 * created by cwj on 2023-10-17
 * Description: A data class that can correspond to sticky titles and list data
 */
data class Contact(val letters: String, val nameList: List<String>)

Complete code:

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.cwj.composedemo.ui.theme.ComposeDemoTheme
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeDemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting()
                }
            }
        }
    }
}

@Composable
funGreeting() {
//Items()
//ItemsIndexed()
//AnyTypeList()
    StickyHeaderTest()
}

/**
 * Sticky title list
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun StickyHeaderTest() {
    val context = LocalContext.current
    val letters = arrayListOf("Type One", "Type Two", "Type Three", "Type Four", "Type Five")
    val contactList = arrayListOf<Contact>()
    val nameList = arrayListOf<String>()
    for (index in 1..5) {
        nameList.add("subitem$index")
    }
    for (index in letters.iterator()) {
        contactList.add(Contact(letters = index, nameList))
    }

    LazyColumn {
        contactList.forEach { (letter, nameList) ->
            stickyHeader {
                Text(
                    text = letter,
                    modifier = Modifier
                        .background(Color.LightGray)
                        .padding(start = 10.dp)
                        .fillMaxWidth(),
                    fontSize = 25.sp
                )
            }

            items(nameList) { contact ->
                Text(
                    text = contact,
                    modifier = Modifier
                        .padding(10.dp)
                        .background(Color.White)
                        .fillMaxWidth()
                        .clickable {
                            Toast
                                .makeText(context, contact, Toast.LENGTH_SHORT)
                                .show()
                        },
                    textAlign = TextAlign.Center,
                    fontSize = 25.sp
                )
            }
        }
    }
}

/**
 *Multiple Type list
 */
@Composable
fun AnyTypeList() {
    val charList = arrayListOf<Chat>()
    charList.apply {
        add(Chat("Hello"))
        add(Chat("What are you doing"))
        add(Chat("I want to ask you something"))
        add(Chat("Nothing done, still writing code!", false))
        add(Chat("What's the matter, brother?", false))
        add(Chat("It's okay..."))
        add(Chat("Okay...", false))
    }

    LazyColumn {
        items(charList) { data ->
            if (data.isLeft) {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 10.dp)
                ) {
                    //Interval setting
                    Spacer(modifier = Modifier.height(10.dp))
                    Row(
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Image(
                            modifier = Modifier
                                .width(35.dp)
                                .height(35.dp)
                                //Cut the circle
                                .clip(CircleShape),
                            painter = painterResource(id = R.drawable.ic_launcher_background),
                            contentDescription = "Left avatar"
                        )
                        Spacer(modifier = Modifier.width(10.dp))
                        Text(
                            data.content,
                            modifier = Modifier
                                .wrapContentWidth()
                                .background(Color.Yellow)
                                .padding(10.dp),
                        )
                    }
                }
            } else {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(end = 10.dp),
                    horizontalAlignment = Alignment.End
                ) {
                    Spacer(modifier = Modifier.height(10.dp))
                    Row(
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Text(
                            data.content,
                            modifier = Modifier
                                .wrapContentWidth()
                                .background(Color.Green)
                                .padding(10.dp)
                        )
                        Spacer(modifier = Modifier.width(10.dp))
                        Image(
                            modifier = Modifier
                                .width(35.dp)
                                .height(35.dp)
                                .clip(CircleShape),
                            painter = painterResource(id = R.drawable.ic_launcher_background),
                            contentDescription = "right avatar"
                        )
                    }
                }
            }
        }
    }
}

/**
 *Basic list two
 */
@Composable
fun ItemsIndexed() {
    val context = LocalContext.current
    val stringList = arrayListOf<String>()
    for (index in 1..50) {
        stringList.add(index.toString())
    }
    LazyColumn {
        //stringList.toArray() method can convert List to Array through List's toArray method
        itemsIndexed(stringList) { index, data ->
            Text(
                text = "My index is: ${index}, my data is: $data",
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 1.dp)
                    .background(Color.White)
                    .clickable {
                        Toast
                            .makeText(context, data, Toast.LENGTH_SHORT)
                            .show()
                    }
            )
        }
    }
}

/**
 *Basic list one
 */
@Composable
funItems() {
    Box(modifier = Modifier.fillMaxSize()) {
        val context = LocalContext.current
        val dataList = arrayListOf<Int>()
        for (index in 1..50) {
            dataList.add(index)
        }

        val listState = rememberLazyListState()
        LazyColumn(state = listState) {
            items(dataList) { data ->
                Text(
                    text = "No. ${data} data",
                    textAlign = TextAlign.Center,
                    //The running effect will be different if the order of property setting is different.
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 1.dp)
                        .background(Color.White)
                        .clickable {
                            Toast
                                .makeText(context, "$data", Toast.LENGTH_SHORT)
                                .show()
                        }
                        .padding(10.dp)
                )
            }
        }

        //Back to top
        val coroutineScope = rememberCoroutineScope()
        Image(
            modifier = Modifier
                .padding(end = 10.dp, bottom = 10.dp)
                .width(45.dp)
                .height(45.dp)
                .clip(CircleShape)
                .align(Alignment.BottomEnd)
                .background(Color.Blue)
                .clickable {
                    coroutineScope.launch {
                        listState.animateScrollToItem(index = 0)
                    }
                },
            painter = painterResource(id = R.drawable.top),
            contentDescription = "Back to top icon"
        )
    }
}

@Preview(showBackground = true, showSystemUi = true)
@Composable
fun GreetingPreview() {
    ComposeDemoTheme {
        Greeting()
    }
}