Adding border to Image after click - kotlin

I want to create a Image that add a border to yourself on onClick trigger. Here is my code:
#Composable
fun Dices(#DrawableRes dice: List<Int>, viewModel: DicesViewModel) {
Column(Modifier.padding(top = 28.dp, start = 10.dp, end = 10.dp, bottom = 26.dp), verticalArrangement = Arrangement.Bottom, horizontalAlignment = Alignment.CenterHorizontally) {
Row() {
Image(
painter = painterResource(id = dice[0]),
contentDescription = "Dice",
modifier = Modifier
.padding(2.dp)
.size(110.dp)
.clickable { Modifier.border(2.dp, Color.Black) /* doesnt work */ })
}
}
I have six more of these Image(), below, but i do not pase it here, because it's the same as here.
There is any way to add border to this?
I want to add a border to Image after click on it

Try this:
var isSelected by remember{ mutableStateOf(false)}
modifier = Modifier
.padding(2.dp)
.size(110.dp)
.border(if (isSelected) 2.dp else 0.dp, Color.Black)
.clickable { isSelected = !isSelected }

Related

How to load bitmap Images in a List faster, Using jetpack compose Android

I am trying to load a list of object in a column using jetpack compose.
The problem is the image is making screen lag.
Here's my code - single list item composable function.
fun SoulProfilePreviewSingleItem(
soul: Souls,
soulWinningViewModel: SoulWinningViewModel,
onClick: () -> Unit
) {
val lazyListState = rememberLazyListState()
/* val localImage = if (soul.localImage.isNotBlank())
rememberImagePainter(getBase64StringToImage(soul.localImage)) else null*/
LaunchedEffect(key1 = soulWinningViewModel.nurtureVsFollowUpTabIndex.value) {
lazyListState.animateScrollToItem(0)
// if (soul.localImage.isNotBlank()){
// }
}
val isManaging = soulWinningViewModel.isManagingList.value
var isDeleted by remember {
mutableStateOf(false)
}
val setVisibility: (Boolean) -> Unit = {
isDeleted = it
}
AnimatedVisibility(
visible = isDeleted.not() &&
if (soulWinningViewModel.userIsSearchingFor.value.isNotEmpty() && isManaging.not())
soul.name.contains(soulWinningViewModel.userIsSearchingFor.value, true) ||
soul.followUpActions.toString()
.contains(soulWinningViewModel.userIsSearchingFor.value, true) else
true
) {
with(soul) {
Column {
Box(
modifier = Modifier
.height(60.dp)
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth(),
contentAlignment = Alignment.BottomEnd
) {
Row(
Modifier
.fillMaxSize(),//.clickable { onClick() },
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.Top,
modifier = Modifier
.padding(start = brc_DP_small)
.padding(bottom = 6.dp, top = 6.dp)
) {
/*if (soul.localImage.isNotBlank()) {
GlideImage(
model = ,
// Crop, Fit, Inside, FillHeight, FillWidth, None
contentScale = ContentScale.Crop,
// shows an image with a circular revealed animation.
)
Log.e("BITMAP","onResourceReady test")
val image = loadPicture(url = soul.localImage, defaultImage = R.drawable.ic_brc_logo).value
image?.let { img->
Image(
// Can crash this
bitmap =img.asImageBitmap(),
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.size(30.dp),
contentScale = ContentScale.Crop
)
}
}*/
if (soul.localImage.isNotBlank()) {
// val imageLoader = rememberImagePainter(getBase64StringToImage(soul.localImage))
Image(
// painter = imageLoader
// Can crash this
bitmap = (
getBase64StringToImage(soul.localImage).asImageBitmap()
),
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.size(30.dp),
contentScale = ContentScale.Crop
)
} else {
Image(
// Can crash this
painterResource(id = R.drawable.ic_brc_logo),
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(50))
.size(30.dp),
contentScale = ContentScale.Crop
)
}
}
Column(
modifier = Modifier
.padding(top = brc_DP_small)
.weight(1f)
.fillMaxWidth()
.fillMaxHeight()
.padding(start = brc_DP_smaller),
verticalArrangement = Arrangement.SpaceBetween
) {
Column(
modifier = Modifier
.weight(1f)
.fillMaxSize()
) {
// This is the place where signle soul is getting showed......
Text(
text = name,
style = if (isManaging.not()) MaterialTheme.typography.labelSmall.copy(
fontWeight = FontWeight(500),
letterSpacing = 0.7.sp
)
else MaterialTheme.typography.labelSmall
.copy(
fontSize = 10.sp
),
modifier = Modifier,
maxLines = 1,
)
if (isManaging.not()) {
Text(
text = SimpleDateFormat(
"dd-MMM-yyyy",
Locale.UK
).format(
createdOn
),
style = MaterialTheme.typography.bodySmall.copy(fontSize = 9.sp),
color = Color.Gray,
modifier = Modifier
)
}
}
if (isBrcMember) {
Text(
text = "BRC Member",
style = MaterialTheme.typography.labelSmall.copy(
fontSize = 7.sp,
fontStyle = FontStyle.Italic
),
color = brc_blue_color,
modifier = Modifier.padding(bottom = brc_DP_smallest)
)
}
}
}
var externClick by remember {
mutableStateOf(false)
}
Column(modifier = Modifier.padding(brc_DP_small)) {
AddSoulFollowUpActionButton(
soul = soul,
soulWinningViewModel = soulWinningViewModel,
visible = soulWinningViewModel.nurtureVsFollowUpTabIndex.value == 1,
externClick = externClick,
onFinished = { externClick = false }
) {
setVisibility(it)
}
}
//TODO:Check Click area ...
Row(modifier = Modifier.fillMaxSize()) {
Spacer(
modifier = Modifier
.fillMaxSize()
.weight(1.4f)
.clickable(
interactionSource = MutableInteractionSource(),
indication = null
) { onClick() })
if (soulWinningViewModel.nurtureVsFollowUpTabIndex.value == 1 || isManaging) {
Spacer(
modifier = Modifier
.fillMaxSize()
.weight(0.6f)
.clickable(
interactionSource = MutableInteractionSource(),
indication = null
) { externClick = !externClick })
}
}
}
Spacer(
modifier = Modifier
.padding(start = 28.dp)
.fillMaxWidth() //.then(if (isManaging.not()) Modifier.width(150.dp) else Modifier.fillMaxWidth())
.height(0.3.dp)
.background(Color.LightGray)
)
}
}
}
}
caller of list composable function.
forEach {
SoulProfilePreviewSingleItem(
soul = it,
soulWinningViewModel
) {
soulWinningViewModel.currentSoul.value = it
navController.navigate(route = SoulWinningRoutes.PROFILE)
}
}
Whenever I am trying to show Image() of my soul object I am getting glitches and my screens takes more time to load itself.
I am storing image as string in local room database and trying to retrieve it back converting it to bitmapImage.
Code for conversation.
fun getBase64StringToImage(base64String: String): Bitmap {
val decodedString: ByteArray = Base64.decode(base64String, Base64.DEFAULT)
val decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size)
return decodedByte
// this is taking a lot of time and making my Ui performance dull.
}
Is there any way I can achieve this functionality with good performance. Like loading Image in separate scope or anything else.
I have already tried using rememberImagePainter and Glide Coil. rememberImagePainter making my performance worst.
Please feel free to give me suggestions, I am still in learning stage.
Thanks in advance.

How do I make lazyVerticalGrid's scroll and column's verticalScroll, scroll together as one

I practicing jetpack compose, where I have a LazyVerticalGrid, a Text and a lazyColumn composeables, which I put in inside another composable which I called HomeContentScreen and gave it a scroll function, and as you know, the LasyVerticalGrid already has a built-in scroll function, which I tried to disable but it affected the scrolling function.
To Summarize; the three composeables scroll differently, depending on which part of the screen I touch.
So my question is how do I make them all follow the same scroll function (vertically)
Here's the codes.
|
Text Composeable;
#Composable
fun HomeQuote() {
Text(
text = stringResource(R.string.Lorem_ipsum),
style = MaterialTheme.typography.h2,
modifier = Modifier
.paddingFromBaseline(top = 24.dp, bottom = 18.dp)
.padding(horizontal = 18.dp)
.heightIn(min = 56.dp)
)
}
|
LazyVerticalGrid Composable;
#Composable
fun SecondBodyGrid(
modifier: Modifier = Modifier,
onHomeCardClick: (Int) -> Unit = {},
) {
LazyVerticalGrid(
columns = GridCells.Fixed(1),
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier
.height(1450.dp)
//.disabledVerticalPointerInputScroll()
.....
|
LazyRow Composable
#Composable
fun FirstBodyRow(
onHomeCardClick: (Int) -> Unit = {},
) {
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(horizontal = 16.dp),
modifier = Modifier
) {
.....
|
And Finally the Composable I arranged everything, HomeContentScreen;
#Composable
fun HomeContentScreen(
modifier: Modifier = Modifier,
onHomeCardClick: () -> Unit
) {
Column(
modifier
.verticalScroll(rememberScrollState())
.padding(vertical = 16.dp)) {
HomeQuote()
HomeTitleSection(title = R.string.favorite_collections) {
SecondBodyGrid {onHomeCardClick()}
}
HomeTitleSection(title = R.string.align_your_body) {
FirstBodyRow {onHomeCardClick()}
}
}

Every element from loop should fill all the free space that is available in the Row

I have elements that I loop through and clicked element changes background to green. I want every element to fill all the free space that is available in the Row. But if I provide weight(1f) it shows only one element that takes all the space, but there should be three elements or whatever count of elements I have passed from outside.
#Composable
fun BottomMenu(
items: List<BottomMenuContent>,
modifier: Modifier = Modifier,
activeHighlightColor: Color = Green,
activeTextColor: Color = Color.White,
inactiveTextColor: Color = Color.Black,
initialSelectedItemIndex: Int = 0
) {
var selectedItemIndex by remember {
mutableStateOf(initialSelectedItemIndex)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.fillMaxWidth()
.background(Gray)
.padding(4.dp)
) {
items.forEachIndexed { index, item ->
BottomMenuItem(
item = item,
isSelected = index == selectedItemIndex,
activeHighlightColor = activeHighlightColor,
activeTextColor = activeTextColor,
inactiveTextColor = inactiveTextColor
) {
selectedItemIndex = index
}
}
}
}
#Composable
fun BottomMenuItem(
modifier: Modifier = Modifier,
item: BottomMenuContent,
isSelected: Boolean = false,
activeHighlightColor: Color = Green,
activeTextColor: Color = Color.White,
inactiveTextColor: Color = Color.Black,
onItemClick: () -> Unit
) {
Row( ) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.clickable {
onItemClick()
}
.background(if (isSelected) activeHighlightColor else Color.Transparent)
.weight(1f)
.padding(top = 14.dp, bottom = 14.dp,)
) {
Text(
text = item.title,
color = if(isSelected) activeTextColor else inactiveTextColor
)
}
}}
Remove the weight from the box and instead put it in its parent Row, I modified your code and please look where the weight is placed.
Your BottomMenu
#Composable
fun BottomMenu() {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(Color.LightGray)
.fillMaxWidth()
) {
(0..7).forEach {
BottomMenuItem()
}
}
}
Your BottomMenuItem
#Composable
fun RowScope.BottomMenuItem() {
Row(
modifier = Modifier.weight(1f) // remove the weight from the box inside and put it over here instead
) {
Box(
modifier = Modifier
.background(Color.Green)
// remove the weigth(1f) from here
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Test",
color = Color.DarkGray
)
}
}
}
Your BottomMenuItem is an extension of a RowScope, so its top level composable can be configured with Row properties such as weight
Output of the code above.

Change the color of the background for each card composable in a lazy list - Jetpack Compose, Android

I am making an app that basically allows the user to search through a list of card composables, each with a heading and a body of text. My question is about changing the color of the background for each card to be a different color from a list of colors I have created. I somehow need to iterate through the list of colors and pass a different color each time and I'm not sure how I do that. Here is some code:
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(color = matte_black)
) {
val list = if (searching) searchResults else allReadings
list.value.let { list ->
items(list.size) { i ->
val reading = list[i]
ReadingItem(reading, **TODO("Add Color")**)
}
}
}
and the composable ReadingItem:
fun ReadingItem(
reading: ReadingData,
**color : Color**
) {
val context = LocalContext.current
val resources = context.resources
val displayMetrics = resources.displayMetrics
val screenWidth = displayMetrics.widthPixels / displayMetrics.density
val spacing = 16.dp
val scroll = rememberScrollState()
Card(
shape = RoundedCornerShape(4.dp),
backgroundColor = color, TODO("This is where i would like the color to iterate through the list")
modifier = Modifier.padding(16.dp)
) {
Column(
modifier = Modifier.width(screenWidth.dp - (spacing * 2)),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start
) {
Text(
text = reading.title,
modifier = Modifier.padding(8.dp),
textAlign = TextAlign.Start,
style = TextStyle(
color = milk_white,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
)
//Spacer(modifier = Modifier.padding(4.dp))
Text(
text = reading.reading,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(8.dp)
.height(100.dp)
.verticalScroll(
state = scroll),
style = TextStyle(
color = milk_white,
fontSize = 16.sp
)
)
}
}
}
and finally, the list of colors:
fun getColors() : List<Color> {
return listOf(
flame_red, orange, ucla_gold, green, tropaz, calypso, plum
)
}
If anyone has any advice it would be very appreciated! Thank you
This should give a basic idea.
Code
#Composable
fun ColourCards() {
val colors = listOf(Color.Blue, Color.Green, Color.Magenta, Color.Gray, Color.Cyan)
LazyColumn {
items(40) {
Box(
Modifier
.fillMaxWidth()
.padding(
horizontal = 16.dp,
vertical = 4.dp,
)
.background(colors[it % colors.size])
.height(80.dp),
)
}
}
}

LazyVerticalGrid item full span width [duplicate]

Just like Sliver in Flutter or StaggeredGridLayoutManager in android reyclerview
so I can insert a banner or some thing else into grid layout
Both item and items have argument span, using which you can specify how many of grid placed each item takes:
val colors = listOf(
Color.Gray,
Color.Red,
Color.Cyan,
Color.Blue,
Color.LightGray,
Color.Yellow,
)
val columnsCount = 3
LazyVerticalGrid(columns = GridCells.Fixed(columnsCount)) {
items(6) {
Box(
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
.background(colors[it])
)
}
items(3, span = { GridItemSpan(columnsCount) }) {
Box(
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
.background(colors[it])
)
}
}
Result: