I will show you how I've created the screen views with Jetpack Componse
for this example
First, lets explain the basics
What is MVVM architecture?
Model — View — ViewModel (MVVM) is the industry-recognized software architecture pattern that overcomes all drawbacks of MVP and MVC design patterns. MVVM suggests separating the data presentation logic(Views or UI) from the core business logic part of the application.
The separate code layers of MVVM are:
- Model: This layer is responsible for the abstraction of the data sources. Model and ViewModel work together to get and save the data.
- View: The purpose of this layer is to inform the ViewModel about the user’s action. This layer observes the ViewModel and does not contain any kind of application logic.
- ViewModel: It exposes those data streams which are relevant to the View. Moreover, it serves as a link between the Model and the View.
What is Jetpack Compose?
Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.
Now we are ready to start with the project!
*Note: In this article I will only explain how the screen views have been defined. If you want to know more, you can check the whole project on Github: JetpackComposeMVVM
Jetpack Compose
To be able to display a list of Categories we first need to define how one category should be displayed. In this case we have the following (code below images):
We also need to understand what are Rows
and Columns
in Jetpack Compose:
- Row: It arranges the views horizontally.
- Column: It arranges the views vertically.
In this case we have a Row to display the Image
, Title
and Description
. But we also have a column which contains the Title
and Description
.
The code for displaying a Category Item is the following:
@Composable
fun CategoryItem(category: Category, context: Context, onClickListener: (Category) -> Unit) {
Card(
modifier = Modifier
.padding(8.dp, 4.dp)
.fillMaxWidth()
.height(300.dp)
.clickable { onClickListener.invoke(category) },
shape = RoundedCornerShape(25.dp),
) {
Surface(
color = Color.LightGray
) {
Row(
Modifier
.padding(4.dp)
.fillMaxSize()
) {
Image(
painter = rememberAsyncImagePainter(
model = category.strThumb,
imageLoader = ImageLoader.Builder(context).crossfade(true).build()
),
contentDescription = category.str,
modifier = Modifier
.fillMaxHeight()
.weight(0.2f)
)
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier
.padding(4.dp)
.fillMaxHeight()
.weight(0.8f)
) {
Text(
text = category.str,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
Text(
text = category.strDescription,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
}
Once we have how one category should look like, we can define how the list should be displayed:
@Composable
fun CategoryList(
categoryList: List<Category>,
context: Context,
onClickListener: (Category) -> Unit
) {
LazyColumn {
itemsIndexed(items = categoryList) { _, item ->
CategoryItem(category = item, context, onClickListener)
}
}
}
In this case we define a LazyColumn
which is a vertically scrolling list that only composes and lays out the currently visible items. It’s similar to a Recyclerview in the classic Android View system.
The result is the following:
Now we need to call CategoryList method in the MainActivity:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MealRecipesTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
CategoryList(categoryList = viewModel.categoryList, context = this) {
val intent = Intent(this@MainActivity, DetailActivity::class.java).apply {
putExtra(DetailActivity.DETAIL_CATEGORY, it)
}
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
startActivity(intent)
}
viewModel.getCategories()
}
}
}
}
}
Note that when a category is clicked, another view will be displayed with the information of the category selected. This can be done because in the CategoryItem compose function we have:
.clickable { onClickListener.invoke(category) }
When clicking on a Category we go to another activity (there is an Intent
in the MainActivity that will be called when the category is clicked).
The new activity, DetailActivity, displays again the Title
,Description
and the Image
.
The compose function looks like this:
@Composable
fun CategoryItem(category: Category, context: Context) {
Surface(
modifier = Modifier
.padding(4.dp)
.fillMaxHeight(),
color = Color.White,
) {
Column(
verticalArrangement = Arrangement.Top,
modifier = Modifier
.padding(20.dp)
.fillMaxHeight()
) {
Text(
text = category.str,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(25.dp)
)
Image(
painter = rememberAsyncImagePainter(
model = category.strThumb,
imageLoader = ImageLoader.Builder(context).crossfade(true).build()
),
contentDescription = category.str,
modifier = Modifier
.fillMaxWidth()
.padding(top = 25.dp)
)
Text(
text = category.strDescription,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.padding(25.dp)
)
}
}
}
Then we need to call CategoryItem function in the DetailActivity:
@AndroidEntryPoint
class DetailActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val category = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getSerializableExtra(DETAIL_CATEGORY, Serializable::class.java) as Category
} else {
@Suppress("DEPRECATION")
intent.getSerializableExtra(DETAIL_CATEGORY) as Category
}
setContent {
MealRecipesTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
CategoryItem(category = category, context = this@DetailActivity)
}
}
}
}
companion object {
const val DETAIL_CATEGORY = "detail_category"
}
}
The result is the following:
And that's all!! That's how you create screen views with Jetpack Compose. Hope you enjoyed!!
If you want to check the whole project here you have the link: JetpackComposeMVVM
Don't forget to like and share! Thank you! :)
Top comments (0)