
This is a UI that contains a list of messages. It is the best example for the Jetpack Compose LazyColumn. It is the XML version of RecyclerView or ListView.
The item in the LazyColumn contains the person’s image, name, time at which the message is sent, and the actual message. All these things are arranged using Column and Row composable.
Jetpack Compose LazyColumn has the following features:
- It shows a ripple with a nice animation when you tap on the list item.
- You can add a header (single item) to the list. In the UI, TopAppbar is the header and list is the list of messages.
- It implements scrolling automatically. You don’t need to set a scrollable modifier. As it is a LazyColumn, it implements vertical scrolling.
The MessagesData is the data class that holds the user image, name, message, and time. All these items are placed inside the Box layout.
Related:
Final output:
If the video isn’t working, watch it on the YouTube.
Helpful links to understand the code:
Here are the Gradle files used in the project.
The images of people are downloaded from Pixabay. Crop them in a square shape before adding to the project.
Here is the source code:
MainActivity.kt:
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.*
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.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
/*
You can use the following code for commercial purposes with some restrictions.
Read the full license here: https://semicolonspace.com/semicolonspace-license/
For more designs with source code,
visit: https://semicolonspace.com/jetpack-compose-samples/
*/
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BlogPostsTheme(darkTheme = false) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Messages1()
}
}
}
}
}
private lateinit var messagesList: ArrayList<MessagesData>
@Composable
fun TopAppbarMessages(context: Context = LocalContext.current.applicationContext) {
TopAppBar(
title = {
Text(
text = "Messages",
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
},
backgroundColor = MaterialTheme.colors.background,
elevation = 4.dp,
navigationIcon = {
IconButton(onClick = {
Toast.makeText(context, "Nav Button", Toast.LENGTH_SHORT).show()
}) {
Icon(
Icons.Filled.ArrowBack,
contentDescription = "Go back",
)
}
}
)
}
@Composable
fun Messages1() {
// This is to check if the messagesList has data or not
// Initially it is false
var listPrepared by remember {
mutableStateOf(false)
}
if (listPrepared) {
TopAppbarMessages()
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
items(messagesList) { itemObject ->
MessagesItemStyle(item = itemObject)
}
}
}
// This is called when the user first opens the activity
// So, add data to messagesList here
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
prepareMessagesList()
listPrepared = true
}
}
}
@Composable
fun MessagesItemStyle(
item: MessagesData,
context: Context = LocalContext.current.applicationContext
) {
Box(
modifier = Modifier
.clickable(
onClick = {
Toast.makeText(context, item.name, Toast.LENGTH_SHORT).show()
}
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
// Profile image
Image(
modifier = Modifier
.clip(shape = CircleShape)
.size(56.dp),
painter = painterResource(id = item.image),
contentDescription = item.name
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = 12.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
// Text that shows the name
Text(
text = item.name,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_medium, FontWeight.Medium)),
fontSize = 18.sp,
color = Color.Black
)
)
// Text that shows the time
Text(
text = item.time,
style = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_regular, FontWeight.Normal)),
fontSize = 14.sp,
color = Color.Black
)
)
}
// Text that shows the message
Text(
modifier = Modifier
.padding(top = 2.dp),
text = item.message,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_regular, FontWeight.Normal)),
fontSize = 16.sp,
color = Color.Black
)
)
}
}
}
}
private fun prepareMessagesList() {
messagesList = ArrayList()
messagesList.add(
MessagesData(
R.drawable.people_abby,
"Abby",
"Cool. We meet tomorrow",
"30 min"
)
)
messagesList.add(
MessagesData(
R.drawable.people_emilia,
"Emilia",
"Why are you not picking up my call?",
"32 min"
)
)
messagesList.add(
MessagesData(
R.drawable.people_emma,
"Emma",
"Tom doesn't have to help",
"40 min"
)
)
messagesList.add(
MessagesData(
R.drawable.people_grace,
"Grace",
"The school principal was so mean that all the children were scared of him",
"3 hours"
)
)
messagesList.add(
MessagesData(
R.drawable.people_hannah,
"Hannah",
"I'm curious to know why they removed my name from the list",
"5 hours"
)
)
messagesList.add(
MessagesData(
R.drawable.people_isabella,
"Isabella",
"Do you really think you'd be happy in a job like that?",
"10 hours"
)
)
messagesList.add(
MessagesData(
R.drawable.people_lucy,
"Lucy",
"Would you like your cash in tens or twenties?",
"12 hours"
)
)
messagesList.add(
MessagesData(
R.drawable.people_olivia,
"Olivia",
"If you hurry, there still might be some choice items left for you to buy",
"1 Nov"
)
)
messagesList.add(
MessagesData(
R.drawable.people_scarlett,
"Scarlett",
"How can she afford a multi-million dollar house?",
"31 Oct"
)
)
messagesList.add(
MessagesData(
R.drawable.people_victoria,
"Victoria",
"She found the necklace in a safe at the bottom of her parents' closet",
"31 Oct"
)
)
}
data class MessagesData(
val image: Int,
val name: String,
val message: String,
val time: String
)