EN VI

Android - How to add items to mutableListOf on click?

2024-03-13 20:30:08
Android - How to add items to mutableListOf on click?

I am trying to build an app that displays a list of goats for a personal project. So far, it's been going smoothly until I reached the part where I need to implement a "+" button that adds new items to the List.

This is what my list looks like:

object DataSource {
    val goats =
        mutableListOf(
            Goats(R.string.red, R.string.alpine, 7),
            Goats(R.string.little_goat, R.string.alpine, 8),
            Goats(R.string.nana, R.string.alpine, 7),
            Goats(R.string.sharkie, R.string.alpine, 10)

        )
     }

Here is the Composable that deals with the Buttons but the code that uses an if statement with isButtonClicked doesn't work. What am I missing?

@Composable
fun GoatsApp(viewModel: MainViewModel) {

    var isButtonClicked by mutableStateOf(false)

    val provider = GoogleFont.Provider(
        providerAuthority = "com.google.android.gms.fonts",
        providerPackage = "com.google.android.gms",
        certificates = R.array.com_google_android_gms_fonts_certs

    )
    val fontName = GoogleFont("Lato")

    val fontFamily = FontFamily(
        Font(googleFont = fontName, fontProvider = provider)
    )
    Column(modifier = Modifier
        .padding(16.dp)
        .fillMaxHeight(0.90f)) {

        Row(
            modifier = Modifier
                .fillMaxWidth(0.95f)
                .border(3.dp, Color.Gray, RoundedCornerShape(13.dp))
        ) {
            Button(
                onClick = { isButtonClicked = true },
                shape = RoundedCornerShape(10.dp),
                modifier = Modifier.background(Color.LightGray)
            ) {
                Text(text = "+")
            }
            Text(
                text = "Does",
                modifier = Modifier
                    .background(color = Color.LightGray)
                    .fillMaxWidth()
                    .padding(12.dp),
                fontStyle = FontStyle.Italic,
                textAlign = TextAlign.Center,
                fontFamily = fontFamily,
                fontWeight = FontWeight.ExtraLight
            )


        }
        Row {
            GoatList(modifier = Modifier.padding(8.dp))
        }

        Row(
            modifier = Modifier
                .fillMaxWidth(0.95f)
                .border(3.dp, Color.Gray, RoundedCornerShape(13.dp))
        ) {
            Button(
                onClick = { isButtonClicked = true },
                shape = RoundedCornerShape(10.dp),
                modifier = Modifier.background(Color.LightGray)
            ) {
                Text(text = "+")
            }
            Text(
                text = "Bucks",
                modifier = Modifier
                    .background(color = Color.LightGray)
                    .fillMaxWidth()
                    .padding(12.dp),
                fontStyle = FontStyle.Italic,
                textAlign = TextAlign.Center,
                fontFamily = fontFamily,
                fontWeight = FontWeight.ExtraLight
            )
        }

        GoatList(modifier = Modifier.padding(8.dp))

        if(isButtonClicked) {
            goats.add(Goats(R.string.little_goat, R.string.alpine, 9)) }

    }


}

This is how the list is displayed and it automatically displays all the items inside it.

    @Composable
fun GoatList(modifier: Modifier = Modifier) {

    LazyVerticalGrid(columns = GridCells.Fixed(1), modifier.padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
        items(goats) { allGoats ->
            GoatCard(allGoats = allGoats, viewModel = MainViewModel())
        }

    }

}

Solution:

In Jetpack Compose, you should not store any state outside of Composables or ViewModels. So the way you defined your object DataSource is not a good practice.

You should instead store your list in a Composable and pass it on to the child Composables that need it. By using mutableStateListOf(), you can create a List where Jetpack Compose can detect when you add a new item, and recompose then.

A typical approach in Jetpack Compose would look like this:

@Composable
fun GoatsApp(viewModel: MainViewModel) {

    val goatList: List<Goats> = remember {
        mutableStateListOf(
            Goats(R.string.red, R.string.alpine, 7),
            Goats(R.string.little_goat, R.string.alpine, 8),
            Goats(R.string.nana, R.string.alpine, 7),
            Goats(R.string.sharkie, R.string.alpine, 10)
        )
    }

    // ...
    Button(
        onClick = { 
            goatList.add(Goats(R.string.little_goat, R.string.alpine, 9))
        },
        shape = RoundedCornerShape(10.dp),
        modifier = Modifier.background(Color.LightGray)
    ) {
        Text(text = "+")
    }

    // ...
 
    GoatList(goats = goatList)
}

Then update your GoatList Composable as follows:

@Composable
fun GoatList(
    modifier: Modifier = Modifier,
    goats: List<Goats>
) {
    LazyVerticalGrid(columns = GridCells.Fixed(1), modifier.padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
        items(goats) { aGoat ->
            GoatCard(allGoats = aGoat, viewModel = MainViewModel())
        }
    }
}
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login