Forgive my lack of knowledge, as I am correcting code to give me the correct numbers from a database. I am normally using java, but was given this file in .kt
val Time: Date,
val duration: Long,
val rate: Long
){
constructor():this(Date(),0,0)
}
#Composable
fun SessionContainer(sessionList: MutableList<MSession>) {
var totalM = 0f
var totalMi = 0f
var mSessions = 0
sessionList.forEach {
if (it.completionTime.time < Calendar.getInstance().time.time)
totalM += it.rate * (it.duration / 1000 / 60 / 60)
else{
totalMi += it.rate * (it.duration / 1000 / 60 / 60)
mSessions++
}
}
Column(
Modifier
.fillMaxWidth()
.padding(12.dp)
) {
Text(text = "Total M [${totalM.toDouble()}]", fontWeight = FontWeight.Bold)
Text(text = "Total Mi [${totalMi.toDouble()}] in total $mSessions sessions", fontWeight = FontWeight.Bold)
}
}
The information in the database is in decimal format. I just need to be able to display it and I do not know how to code kotlin. I made a change already that is now displays "0.0" instead of "0", but there should be a number with those decimals(i.e. 123.4567)
In the code, totalM and totalMi are float variables. If you want to display the decimal value, you need to format the value to a string with a specific number of decimal places.
Here's how you can format the decimal value with 4 decimal places:
Text(text = "Total M [${String.format("%.4f", totalM)}]", fontWeight = FontWeight.Bold)
Text(text = "Total Mi [${String.format("%.4f", totalMi)}] in total $mSessions sessions", fontWeight = FontWeight.Bold)
Related
I'm developing an Android app using Jetpack Compose.
I'd like to set a character count limit on Textfield, but if I try this code, users can input maximum 1201 characters(maxChar+1), and if users input 1201 characters(exceed maxChar), they cannot delete any letters.
#Composable
fun PostEdit(navController: NavController, content: String, id: String) {
var editedContent = remember { mutableStateOf("$content")}
val maxChar = 1200
...
OutlinedTextField(
value = editedContent.value,
onValueChange = { newValue: String ->
if (editedContent.value.length <= maxChar) {
editedContent.value = newValue
}
},
label = { Text("Content", fontSize = 20.sp, color = Brown) },
...
On a different view, I set a character count limit, too, and it is successful. The difference is, this time, there is no parameter in "var intro". This is the code.
#Composable
fun Signup(navController: NavController)
var intro by remember { mutableStateOf("") }
val maxChar = 100
...
OutlinedTextField(
value = intro,
onValueChange = {
if (it.length <= maxChar) {
intro = it
}
},
label = { Text("Introduction", fontSize = 20.sp, color = Brown) },
...
Could someone help me? Thank you.
The second one (intro) you are using the implicit it parameter not the intro state variable
onValueChange = { // <-- implicit `it`
if (it.length <= maxChar) {
intro = it
}
}
while on the first (editedContent) one you are using the state variable instead so when editedContent's length reaches 1200 and you typed another character it will still satisfy your onValueChange condition <=, making it 1201, and when you attempt to delete, the condition won't be satisfied anymore, no changes will happen to editedContent
onValueChange = { newValue: String -> // <-- use this
if (editedContent.value.length <= maxChar) {
editedContent.value = newValue
}
}
so do what you did on the second one to your first one and it will work
onValueChange = { newValue: String ->
if (newValue.length <= maxChar) {
editedContent.value = newValue
}
}
I am currently developing a Sokoban game in Kotlin for an Android app and at this point I have an algorithm that generates a matrix of strings where each string refers to a specific game element, e.g., "#" - Wall, "0" - Floor, "#" - Player, "$" - Box, etc...
Based on that matrix, I am using Jetpack Compose to draw in a canvas rectangles with different colors so I can distinguish the elements (wall, floor, ...) of the Sokoban game.
At the moment, this is the result:
Elements represented by rectangles
However, my final goal is to replace that colored rectangles, with images (.png files). Example:
Expected result
How can I do that?
Here's my code:
class SokobanActivity : AppCompatActivity() {
private lateinit var mGameMatrix: Array<Array<String>>
...
#Composable
fun GameCanvas() {
Canvas(
modifier = Modifier
.fillMaxSize()
) {
drawRect(color = Color.Black)
val squareDim = 64.dp.value
(mGameMatrix.indices).forEach { i ->
(mGameMatrix[i].indices).forEach { j ->
val element = mGameMatrix[i][j]
drawGameElement(
squareColor = when (element) {
//Wall
"#" -> Color.Red
//Floor
"0" -> Color.Cyan
//Box
"$" -> Color.Green
//Box-objective
"." -> Color.Yellow
//Player
"#" -> Color.Magenta
else -> Color.Blue
},
Offset(
(i * squareDim) + ((size.width - (mGameMatrix.size * squareDim)) / 2),
(j * squareDim) + ((size.height - (mGameMatrix.size * squareDim)) / 2)
),
size = Size(
width = squareDim,
height = squareDim
)
)
}
}
}
}
private fun DrawScope.drawGameElement(
squareColor: Color,
offset: Offset,
size: Size,
) {
drawRect(
color = squareColor,
topLeft = offset,
size = size
)
}
...
}
You can just draw your vector, png etc. resources on Canvas, like that:
val image = ImageVector.vectorResource(id = iconRes)
val painter = rememberVectorPainter(image = image)
translate(
left = size.width / 2 - painter.intrinsicSize.width / 2,
top = size.height / 2 - painter.intrinsicSize.height / 2
) {
with(painter) {
draw(painter.intrinsicSize)
}
}
Is there any out of the box solution for limiting the character size in TextField's ?
I don't see any maxLength parameter like we had in XML.
With 1.x.y there isn't a built-in parameter.
You can use something like:
var text by remember { mutableStateOf(TextFieldValue("")) }
val maxChar = 5
TextField(
singleLine = true,
value = text,
onValueChange = {
if (it.length <= maxChar) text = it
}
)
To display the counter text you can use something like:
val maxChar = 5
Column(){
TextField(
value = text,
onValueChange = {
if (it.length <= maxChar) text = it
},
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
Text(
text = "${text.length} / $maxChar",
textAlign = TextAlign.End,
style = MaterialTheme.typography.caption,
modifier = Modifier.fillMaxWidth().padding(end = 16.dp)
)
}
The first answer to this question works fine, but it´s true that in some cases there is an error that when exceeding the number of characters allowed, the value of the texfield is cleared. This failure seems to be due to predictive text, because if predictive text is disabled in android, it does not happen. One solution I found for now as a workaround is to use focusManager to "limit writing".
First, we need to get the focus manager to control the focus on the screen.
We can do this, by adding this line inside our composable function:
val focusManager = LocalFocusManager.current
Then, in our TextField we can use the focusManager to avoid the user to write more than the maxChar limit. We can move the focus to the next element, clear the focus when the maxChar limit is exceeded or receive a lambda function and perform the action we want . That depends on us.
var text by remember { mutableStateOf(TextFieldValue("")) }
val maxChar = 10
TextField(
singleLine = true,
value = text,
onValueChange = {
// This line will take (in case the user try to paste a text from the clipboard) only the allowed amount of characters
text = it.take(maxChar)
if (it.length > maxChar){
focusManager.moveFocus(FocusDirection.Down) // Or receive a lambda function
}
}
)
In this way the user could never write more characters than what is established by the limit. Obviously, this is an alternative solution, which in my case solved my problem, now we have to wait to see if they add it natively
Trim the most recently inserted character according to selection, if the new string exceeds the length.
fun TextFieldValue.ofMaxLength(maxLength: Int): TextFieldValue {
val overLength = text.length - maxLength
return if (overLength > 0) {
val headIndex = selection.end - overLength
val trailIndex = selection.end
// Under normal conditions, headIndex >= 0
if (headIndex >= 0) {
copy(
text = text.substring(0, headIndex) + text.substring(trailIndex, text.length),
selection = TextRange(headIndex)
)
} else {
// exceptional
copy(text.take(maxLength), selection = TextRange(maxLength))
}
} else {
this
}
}
Usage:
val (phone, setPhone) = remember {
mutableStateOf(TextFieldValue())
}
PaddingTextField(
value = phone,
onValueChange = { newPhone ->
setPhone(newPhone.ofMaxLength(11))
}
)
You can use take function - here documentation
onValueChange = { onYearChanged(it.take(limitNum)) })
For example, if you will use it in function.
const val limitNum = 4
#Composable
fun YearRow(
modifier: Modifier = Modifier,
year: Int,
onYearChanged: (String) -> Unit,
) {
OutlinedTextField(
modifier = modifier,
value = if (year == 0) "" else "$year",
onValueChange = { onYearChanged(it.take(limitNum)) },
)
}
Another way to do this that could be considered more flexible is something like:
Text(
text = "A string with a lot of charsssssssssssssssssssssssssss"
modifier = Modifier.fillMaxWidth(.5f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
this will constraint the width with the fillMaxWidth bit and the height with the maxLines part. If both of those constraints are hit the text will overflow and the behavior for overflow can be specified
in this case once the text occupied half of the view or went more than one line it would end up something like A string with a lot of charsssss...
This question already has answers here:
How to convert String to Int in Kotlin?
(11 answers)
Closed 1 year ago.
fun Add() {
var num1 by remember { mutableStateOf("") }
var num2 by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Arrangement.CenterHorizontally,
) {
TextField(
value = num1,
onValueChange = { num1 = it })
TextField (value = num2, onValueChange = { num2 = it })
}
remember { mutableStateOf("") }
val sum = num1 + num2
Column(
modifier = Modifier.fillMaxsize(), verticalAlignment = Alignment.End
) {
Button(onClick = {
Toast.maketext(
context,
"result:$sum",
Toast.LENGTH_SHORT
).show()
}) { Text("output") }
}
}
I'm getting output as concatenated values eg: 5 + 5 = 55 but I need out put as 5 + 5 = 10 sum of numbers.
This is no different than any other string to number conversion, instead of
val sum = num1 + num2
do
val sum = (num1.toInt() + num2.toInt()).toString()
Use use num1.toInt() and num2.toInt() to add the numbers up.
I'm trying to set min and max progress of CircularProgressIndicator But I couldn't found any solution.
This is the given Composable CircularProgressIndicator:
#Composable
fun CircularProgressIndicator(
/*#FloatRange(from = 0.0, to = 1.0)*/
progress: Float,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colors.primary,
strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth
) {
val stroke = with(LocalDensity.current) {
Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Butt)
}
Canvas(
modifier
.progressSemantics(progress)
.size(CircularIndicatorDiameter)
.focusable()
) {
// Start at 12 O'clock
val startAngle = 270f
val sweep = progress * 360f
drawDeterminateCircularIndicator(startAngle, sweep, color, stroke)
}
}
It only accepts progress in the range of float which 0.0 to 1.0 I want to change this to accept value from 0 to 100.
Note:
I also found out this Modifier.progressSemantics But I don't know how to use it to change the progress range.
#Stable
fun Modifier.progressSemantics(
value: Float,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
/*#IntRange(from = 0)*/
steps: Int = 0
): Modifier {
val progress = (
if (valueRange.endInclusive - valueRange.start == 0f) 0f
else (value - valueRange.start) / (valueRange.endInclusive - valueRange.start)
).coerceIn(0f, 1f)
// We only display 0% or 100% when it is exactly 0% or 100%.
val percent = when (progress) {
0f -> 0
1f -> 100
else -> (progress * 100).roundToInt().coerceIn(1, 99)
}
return semantics {
stateDescription = "$percent percent"
progressBarRangeInfo =
ProgressBarRangeInfo(value.coerceIn(valueRange), valueRange, steps)
}
}
Any help is appreciated.
In your case you don't need to change the progress range.
Just turn your range into 0.0 - 1.0.
Just divide the progress value by 60000.
1000/60000 = 0.016 for each tick.
If you want to reverse the count just use something like:
val progress = 1 - (givenValueOnTick.toFloat / 60000)