UI doesn't update when mutableStateOf changes - kotlin

I have #Composable item - ThumbButton and Text which displays current likes number. When I click button I want to increment likes number. I don't know why it doesn't work
val likesCounter = remember { mutableStateOf(0)}
Row(
modifier = Modifier.wrapContentSize(),
verticalAlignment = Alignment.CenterVertically
) {
ThumbButton(
iconSize = sizeButton,
isSelected = isActive,
onClick = { likesCounter.value = likesCounter.value+1 }
)
Text(text = "($likesCounter)")
}

Try referencing the value property while displaying it?
Text(text = "(${likesCounter.value})")

Related

Compose onValueChange behaviour isn't consistent

I'm making a sudoku game and solver. For my user interface I used LazyVerticalGrid to create a 9x9 grid. I successfully made it so when you click on a cell it will only accept digits [1-9] via an OutLinedTextField. I then added a conditional that only empty cells would have the text field applied. That worked and only those cells could be altered but when I do that the logic that only accepts digits doesn't work and the program crashes. If I comment out the conditional statement and the OutLinedTextField is applied to all cells it works again. I get the following error.
Also if I add conditionals for backgroundColor or Content Color the same thing happens and the program crashes if a non digit is pressed. I'm not sure why the conditionals affect the onValueChange logic. Why is this and how do I fix it?
fun displayPuzzle(answer: Array<Array<IntArray>>) {
var list: SnapshotStateList<String> = mutableStateListOf()
for (x in answer[0]) list.addAll(x.map { it.toString() })
var columnHeighty by remember { mutableStateOf(0F) }
var columnWidthx by remember { mutableStateOf(0f) }
var pad = 20.dp
LazyVerticalGrid(
columns = GridCells.Fixed(9),
contentPadding = PaddingValues(
start = pad,
top = pad,
end = pad,
bottom = pad
)
) {
items(list.size) { index ->
Card(
shape = RectangleShape,
backgroundColor = Color.Red,
modifier = Modifier
.requiredWidth(83.dp)
.fillMaxWidth()
.fillMaxHeight()
.onGloballyPositioned { coordinates ->
columnWidthx = coordinates.size.width.toFloat()
columnHeighty = coordinates.size.height.toFloat()
},
//backgroundColor = if (list[index].toInt() == 0) Color.Yellow else Color.White ,
//contentColor = if (list[index].toInt() == 0) Color.Blue else Color.Black ,
border = BorderStroke(width = 1.dp, color = Color.Black)
) {
Text(
text = list[index],
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
color = Color(0xFF000000),
textAlign = TextAlign.Center,
modifier = Modifier
.padding(23.dp)
.clickable { }
)
}
// When the if statement is included the program crashes on a non digit entry
//if (list[index].toInt() == 0) {
val pattern = remember { Regex("[1-9]") }
var value by remember { mutableStateOf("") }
OutlinedTextField(
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
colors = TextFieldDefaults.outlinedTextFieldColors(cursorColor = Color.Transparent),
textStyle = TextStyle(color = Color.Red),
modifier = Modifier
.fillMaxHeight()
.padding(vertical = 10.dp, horizontal = 10.dp),
value = value,
onValueChange = { if (it.isEmpty() || (it.matches(pattern) && (it.length == 1)))
value = it
list[index] = value}
)
//}
}
}
Your game crashed because you trying to convert for example 'a' to Int value and runtime throws NumberFormatException.
You need to use:
if (list[index].toIntOrNull() == null)
This condition will be triggered if a non-decimical number is obtained from your SnapshotStateList
Explanation: toIntOrNull() returns Int from String (example: "4".toIntOrNull() - returns 4) otherwise it returns null

How to align VerticalPager page with pager indicators?

Pager indicator and pager are in two separate libraries. I've been unable to get the indicators to sit to the right of the page.
#OptIn(ExperimentalPagerApi::class)
#Composable
fun Photos(photos: List<String>){
val state = rememberPagerState()
Row{
VerticalPager(count = photos.size, state = state, contentPadding = PaddingValues(vertical = 32.dp)) {
AsyncImage(model = photos[it], contentDescription = null, modifier = Modifier.fillMaxSize())
}
VerticalPagerIndicator(pagerState = state)
}
}
I've tried setting a custom width for the AsyncImage but it's not giving me what I'm expecting which is enough space for the indicator to sit horizontally next to the page.
Set verticalAlignment to Alignment.CenterVertically, it's Alignment.Top by default
Row(
verticalAlignment = Alignment.CenterVertically
){
VerticalPager(count = photos.size, state = state, contentPadding = PaddingValues(vertical = 32.dp)) {
AsyncImage(model = photos[it], contentDescription = null, modifier = Modifier.fillMaxSize())
}
VerticalPagerIndicator(pagerState = state)
}

How can i make this animation stop after completion in Jetpack Compose or not be infinite

#Composable
fun Gojo(
maxWidth:Dp,
maxHeight:Dp,)
{
val resource: Painter
val modifier: Modifier
val gojoSize = 200.dp
val infiniteTransition = rememberInfiniteTransition()
val posistionState = infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = LinearEasing
),
repeatMode=RepeatMode.Reverse
)
)
if(posistionState.value<=0.1f) {
modifier = Modifier.offset(
x = -140.dp,
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else if(posistionState.value<=0.2f){
modifier = Modifier.offset(
x = -100.dp,
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else if(posistionState.value<=0.25f){
modifier = Modifier.offset(
x = -100.dp,
y = maxHeight * 0.75f,
).rotate(0.0F)
}
else if(posistionState.value<=0.3f){
modifier = Modifier.offset(
x = -100.dp+(maxWidth*posistionState.value),
y = maxHeight * 0.75f,
).rotate(50.0F)
}
else{
modifier = Modifier.offset(
x = maxWidth * 0.25f,
y = maxHeight * 0.75f,
)
}
resource=painterResource(R.drawable.gojo)
Image(modifier=modifier.width(gojoSize).height(gojoSize),painter = resource, contentDescription ="gojo sama")
}
you are asking for not to be infinite and using infinite transition? just use animateDpAsState and change size of the image by using the dp values. If you want to start the transition when the item has composed just call a LaunchedEffect (true) {startTransition = true} by remembering the startTransition value as false in the beginning:
var startTransition by remember {
mutableStateOf(false)
}
LaunchedEffect(true){
startTransition = true
}
val size = animateDpAsState(
targetValue = if(startTransition == false)
0.dp
else
/*Your Desired Value*/
)
// And use size in Image. You can create different animateDpAsState values for width and height.

Why does HorizontalPager's automatic scrolling stop after manual scrolling?

I have a HorizontalPager
val pageCount = bannerList.size
val startIndex = Int.MAX_VALUE / 2
val pagerState = rememberPagerState(initialPage = 100)
HorizontalPager(
count = Int.MAX_VALUE,
state = pagerState,
contentPadding = PaddingValues(
horizontal = 20.dp
),
modifier = Modifier
.fillMaxWidth()
) { index ->
// content goes here
}
and I made it scrolling every 4 second like banners with LaunchedEffect
LaunchedEffect(
key1 = Unit,
block = {
repeat(
times = Int.MAX_VALUE,
action = {
delay(
timeMillis = 4000
)
pagerState.animateScrollToPage(
page = pagerState.currentPage + 1
)
}
)
})
it scrolls fine every 4 second but when i scroll it manually HorizontalPager stops scrolling!
any suggestions how to fix this?
animateScrollToPage throws an exception when called during manual scrolling:
java.util.concurrent.CancellationException: Current mutation had a higher priority
You can solve it in many ways. For example just catch the exception and ignore it:
delay(
timeMillis = 4000
)
try {
pagerState.animateScrollToPage(
page = pagerState.currentPage + 1
)
} catch (_: Throwable) {
}
An other option is to check whether the pager is being dragged and stop your LaunchedEffect for this period of time:
val isDragged by pagerState.interactionSource.collectIsDraggedAsState()
if (!isDragged) {
LaunchedEffect(Unit) {
// ...
}
}
I think the second solution is cleaner, because in this case the timer will be restarted, and delay until the next scroll will always be the same.

Jetpack Compose offset image vector in Canvas

I have a problem with vector image in Canvas. As shown below I can just call vector image but I can’t make any offset in Canvas. So I only can have it the way it is.
I don't know the reason why there is no Offset option like in drawCircle or drawRect, if someone has some ideas it would be great.
val vector = ImageVector.vectorResource(id = R.drawable.ic_test)
val painter = rememberVectorPainter(image = vector)
Box(contentAlignment = Alignment.Center) {
Canvas(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
) {
with(painter) {
draw(
painter.intrinsicSize
)
}
}
}
I tried something like adding Offset into with(painter) but nothing changes:
with(painter) {
draw(
painter.intrinsicSize
)
Offset(x = 10f, y = 10f)
}
You can use DrawScope.translate:
translate(left = 10f, top = 10f) {
with(painter) {
draw(
painter.intrinsicSize
)
}
}