如果android jetpack compose中的[图像卡]和[名片]都是正确的键值对,如何更改onClick上的卡片颜色?

问题描述 投票:0回答:2

所以,我有两列,其中一列包含所有图像,另一列包含与这些图像关联的所有名称。简而言之,图像是键,名称是值,但名称是随机生成和显示的,它们不是按顺序显示的。用户需要单击第一列中的一张卡片,然后单击第二列中的正确名称。所以,我想要的是;当我单击第一列[图像卡]中的一张卡片时,它的背景颜色应该变成绿色,同时如果我从其他列单击正确的[名片],它的背景也应该变成绿色,或者它的背景应该变成红色。我尝试通过使用记住并存储 selectedImageId 的值来实现它,但我的应用程序崩溃了。下面是我的屏幕

下面是我的 Activity 的代码MainActivity.kt

package com.example.composegrid

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
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.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role.Companion.Image
import androidx.compose.ui.text.TextStyle
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 androidx.lifecycle.viewmodel.compose.viewModel
import com.example.composegrid.ui.theme.ComposeGridTheme

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.text.font.FontWeight

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



@Composable
fun PlayScreen() {
    // Generate the list of images and names as key-value pairs
    val imageNamesMap = generateImageNamesMap()

    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colorScheme.background
    ) {
        // Center the Row in the screen
        Row(
            modifier = Modifier.fillMaxSize(),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            // First column for images (keys)
            CardColumn(imageNamesMap.keys.toList())

            // Second column for names (values)
            CardColumn(imageNamesMap.values.toList(), true)
        }
    }
}



@Composable
fun CardColumn(items: List<Any>, isNamesColumn: Boolean = false) {
    LazyColumn(
        modifier = Modifier.padding(start = if (isNamesColumn) 16.dp else 0.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(items) { item ->
            Card(modifier = Modifier.size(100.dp).padding(start = 30.dp, top = 20.dp)) {
                if (isNamesColumn) {
                    NameItem(name = item as String)
                } else {
                    ImageItem(imageResId = item as Int)
                }
            }
        }
    }
}


fun generateImageNamesMap(): HashMap<Int, String> {
    // Add image resources to a list
    val images = listOf(
        R.drawable.he,
        R.drawable.how,
        R.drawable.what,
        R.drawable.we,
        // Add more image resources as needed
    )

    // Add image names to a list in random order
    val imageNames = listOf(
        "Name1",
        "Name2",
        "Name3",
        "Name4",
        "Name5"
        // Add more image names corresponding to the resources
    )

    // Shuffle the image names list randomly
    val shuffledNames = imageNames.shuffled()

    // Use the shuffled names to assign each image resource ID a corresponding name in the imageNamesMap
    val imageNamesMap = HashMap<Int, String>()
    for (i in images.indices) {
        imageNamesMap[images[i]] = shuffledNames[i]
    }

    return imageNamesMap
}

@Composable
fun ImageItem(imageResId: Int) {
    val painter: Painter = painterResource(id = imageResId)
    Image(
        painter = painter,
        contentDescription = null, // Provide proper content description if needed
        modifier = Modifier
            .size(120.dp)
            .padding(8.dp)
    )
}

@Composable
fun NameItem(name: String) {
    Text(
        text = name,
        style = TextStyle(
            fontSize = 16.sp,
            fontWeight = FontWeight.Bold,
            color = MaterialTheme.typography.bodyMedium.color,
            textAlign = TextAlign.Center
        ),
        modifier = Modifier
            .padding(8.dp)
    )
}


@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeGridTheme {

        PlayScreen()

    }
}

下面是数据类ImageInfoData所需的代码

package com.example.composegrid

data class ImageInfoData(val imageResId:Int,val imageName:String)
android kotlin android-jetpack-compose android-cardview
2个回答
0
投票

创建一个 Ui 状态数据类,该数据类将被初始化为 MutableStateFlow() 对象,并将被collectAsStateWithLifeCycle() 并将其传递给子可组合项。以及一个事件类,其中包含用户交互事件,例如选择的图像和选择的名称。 uiState 类示例:

data class PlayScreenUiState(
  val selectedImage : Int? = null,
  val selectedName : String? = null,
  
)
interface PlayScreenEvent{

  data class ImageSelected(val imageId : Int) : PlayScreenEvent

  data class NameSelected(val name : String) : PlayScreenEvent

}

以下是您根据活动领取零钱的方式。

class MainViewModel : ViewModel(){

  private val _playScreenUiState  = MutableStateFlow(PlayScreenUiState())
  val playScreenUiState  = _playScreenUiState.asStateFlow()

  fun onEvent(event : PlayScreenEvent) {

  is PlayScreenEvent.ImageSelected -> {
         _playScreenUiState.update {
               it.copy(
                  selectedImage = it.imageId
             )
      }
   }

  is PlayScreenEvent.NameSelected-> {
         _playScreenUiState.update {
               it.copy(
                  selectedName = it.name
             )
      }
   }
}

}


创建 viewModel 收集状态并传递给子可组合项。

val viewModel : MainViewModel by viewModels()
val uiState by viewModel.playerScreenUiState.collectAsStateWithLifecylce()


PlayScreen(uiState,viewModel::onEvent)
@Composable
fun PlayScreen(
   uiState : PlayScreenUiState,
   onEvent : (PlayScreenEvent) -> Unit
) {
   var imageBackGroundColor by remember{
           mutableStateOf(Color.White)
    }
    var textBackGroundColor by remember{
           mutableStateOf(Color.White)
    }

    if(uiState.selectedImage != null && uiState.selectedImage != null){

       //check if both the values are correct according to the hashmap and
        //change both the background color to green or red accordingly


       
     }

    //similarly check the condition where only one of the is selected and set it the background to red.
}

0
投票

我不太清楚你的问题,但你可能想尝试这种方法来达到与此类似的预期结果RESULT
您必须使用记住功能来存储所选的图像 ID 和名称 ID,如下所示:

var selectedImageId by remember { mutableStateOf(-1) }

var selectedNameValue by remember { mutableStateOf("") }

CardColumn 可组合项中的 isSelected 变量用于跟踪是否选择了卡片,并相应地设置背景颜色。

更新:完整代码

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
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.example.myapplication.ui.theme.MyApplicationTheme

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


@Composable
fun PlayScreen() {
    var selectedImageId by remember { mutableStateOf(-1) }
    var selectedNameValue by remember { mutableStateOf("") }

    // Generate the list of images and names as key-value pairs
    val imageNamesMap = generateImageNamesMap()
    var randomKeys by remember { mutableStateOf(imageNamesMap.values.toList().shuffled()) }

    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colorScheme.background
    ) {
        // Center the Row in the screen
        Row(
            modifier = Modifier.fillMaxSize(),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            // First column for images (keys)
            CardColumn(
                imageNamesMap.keys.toList(),
                isNamesColumn = false,
                selectedId = selectedImageId,
                onCardClick = { selectedImageId = it as Int }
            )

            // Second column for names (values)
            CardColumn(
                randomKeys,
                isNamesColumn = true,
                selectedId = selectedNameValue,
                onCardClick = {
                    selectedNameValue = if (imageNamesMap.getOrDefault(selectedImageId, "") == it) {
                        it // Unique ID for name
                    } else {
                        "" // Reset if it's incorrect
                    }
                }
            )
        }
    }
}

@Composable
fun CardColumn(
    dataImage: List<Any>,
    isNamesColumn: Boolean = false,
    selectedId: Any,
    onCardClick: (Any) -> Unit
) {
    LazyColumn(
        modifier = Modifier.padding(start = if (isNamesColumn) 16.dp else 0.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(dataImage) { item ->
            val isSelected = if (isNamesColumn) {
                item.toString() == selectedId as String
            } else {
                item as Int == selectedId as Int
            }

            Card(
                modifier = Modifier
                    .size(100.dp)
                    .padding(start = 30.dp, top = 20.dp)
                    .clickable { onCardClick(item) },
                colors = CardDefaults.cardColors(containerColor = if (isSelected) Color.Green else Color.LightGray)
            ) {
                if (isNamesColumn) {
                    NameItem(name = item as String, isSelected = isSelected)
                } else {
                    ImageItem(imageResId = item as Int, isSelected = isSelected)
                }
            }
        }
    }
}

data class ImageInfoData(val imageResId: Int, val imageName: String)

@Composable
fun ImageItem(imageResId: Int, isSelected: Boolean) {
    val painter: Painter = painterResource(id = imageResId)
    Image(
        painter = painter,
        contentDescription = null,
        modifier = Modifier
            .size(120.dp)
            .padding(8.dp),
        contentScale = ContentScale.Crop,
        alignment = if (isSelected) Alignment.TopCenter else Alignment.Center
    )
}


fun generateImageNamesMap(): Map<Int, String> {
    // Add image resources to a list
    val images = listOf(
        R.drawable.account_avatar_1,
        R.drawable.account_avatar_2,
        R.drawable.account_avatar_3,
        R.drawable.account_avatar_4,
        // Add more image resources as needed
    )

    // Add image names to a list in random order
    val imageNames = listOf(
        "Name1",
        "Name2",
        "Name3",
        "Name4",
        // Add more image names corresponding to the resources
    )

    // Use the 'zip' function to pair the images with the shuffled names and then convert it to a map
    return images.zip(imageNames).toMap()
}


@Composable
fun NameItem(name: String, isSelected: Boolean) {
    Text(
        text = name,
        style = TextStyle(
            fontSize = 16.sp,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Center
        ),
        modifier = Modifier
            .padding(8.dp)
            .fillMaxWidth(),
    )
}
© www.soinside.com 2019 - 2024. All rights reserved.