RangeSlider fills all available width in Jetpack Compose - android-jetpack-compose

When I am trying to put some composable after RangeSlider, RangeSlider fills all width.
For example:
Row {
Text(text = "Test1")
var range by remember { mutableStateOf(-20f..20f) }
RangeSlider(
values = range, onValueChange = {
range = it
},
colors = SliderDefaults.colors(
thumbColor = MaterialTheme.colorScheme.onSecondaryContainer,
activeTrackColor = MaterialTheme.colorScheme.onSecondaryContainer
),
valueRange = -50f..50f
)
Text(text = "Test2")
}
In this case Text with Test2 is invisible.
When I am trying to force RangeSlider to be with some width, second slider is out of track. Also, Modifier.weigth() does not work.

Using another Layout that wraps RangeSlider solves the issue. Don't know why RangeSlider does not abide Modifier.weigth()
Row {
Text(text = "Test1")
var range by remember { mutableStateOf(-20f..20f) }
Row(
modifier= Modifier.weight(1f),
){
RangeSlider(
values = range, onValueChange = {
range = it
},
valueRange = -50f..50f
)
}
Text(text = "Test2")
}

Related

How to increase the track height of a slider in material design 3

#Composable
fun SliderWithCustomTrackAndThumb() {
var sliderPosition by remember { mutableStateOf(0f) }
val interactionSource = MutableInteractionSource()
val colors = SliderDefaults.colors(thumbColor = Color.Red, activeTrackColor = Color.Red)
Column {
Text(text = sliderPosition.toString())
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
interactionSource = interactionSource,
thumb = {
SliderDefaults.Thumb(
interactionSource = interactionSource,
colors = colors
)
},
track = { sliderPositions ->
SliderDefaults.Track(
colors = colors,
sliderPositions = sliderPositions
)
}
)
}
}
The above composable function creates a sample slider with a custom thumb size. I want to increase the size of the track. how can I do that?
while you can't change the size size of the track set in the SlideDefaults.Track()component, you can always provide your own track implementation by copying the code from the SliderDefaults and change the track size there.

ImeAction moves cursor to the beginning of a TextField

When i click "Next" ImeAction, the cursor position goes to a previous remembered position (i.e. if you ever manually set a cursor position) for newly selected TextField. If there was none, then the cursor jumps to the start, even though the TextField is not empty. I expected the cursor always be in the end, when focus was gained via ImeAction.
Sample code (for simplicity i hold mutable states right here, not using ViewModel):
#Composable
fun ImeActionIsBroken() {
val focusRequester = remember { FocusRequester() }
Column {
var value1 by rememberSaveable { mutableStateOf("Some value 1") }
TextField(
value = value1,
onValueChange = { value1 = it },
modifier = Modifier.fillMaxWidth(),
keyboardActions = KeyboardActions {
focusRequester.requestFocus()
},
singleLine = true
)
var value2 by rememberSaveable { mutableStateOf("Some value 2") }
TextField(
value = value2,
onValueChange = { value2 = it },
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
singleLine = true
)
}
}
Compose version 1.0.5
You can use the TextFieldValue object instead of using String for our TextField. With that, you can customize the selected range of text / or where the text cursor should be.
In your example, you should move up the declaration of the value2 to be accessible by the KeyboardAction callback of the first text field.
Then update it to be a TextFieldValue, like so :
var value2 by rememberSaveable { mutableStateOf(TextFieldValue("Some value 2")) }
And inside the KeyboardAction you can just update the selection to be at the end of the field, before requesting the focus, like that :
value2 = value2.copy(selection = TextRange(value2.text.length))
focusRequester.requestFocus()

Compose - TextField - SelectAllOnFocus

If we want our TextField to have an equivalent behaviour to EditText:selectAllOnFocus = "true" we can do something like create a TextFieldValue and set the selection from zero to lenght like TextRange(0, text.length)
This works and when user focus the TextField the whole text get selected, the problem is that when we create a TextFieldValue we need to set selection, the default value is Zero.
If the user wants to drag the cursor he just cant. Is there a way for now to create a selectAllOnFocus behaviour that allows the user to drag the cursor all over the text if he wants to in compose?
Yes I think one way is to follow the result selection coming from the TextField onValueChange callback:
var editableText by rememberSaveable { mutableStateOf("some text") }
val textRangeStart = rememberSaveable { mutableStateOf(0) }
val textRangeEnd = rememberSaveable { mutableStateOf(0) }
val textField = remember(editableText, textRangeEnd.value, textRangeStart.value) {
mutableStateOf(
TextFieldValue(
text = editableText ?: "",
selection = TextRange(textRangeStart.value, textRangeEnd.value)
)
)
}
TextField(
modifier = Modifier.fillMaxSize(),
value = textField.value,
placeholder = { Text("") },
onValueChange = {
textEditorViewModel.editableText.value = it.text
textRangeStart.value = it.selection.start
textRangeEnd.value = it.selection.end
}
)
}

DatePicker textvalue is updating to one day prior instead of date selected

I'm trying to implement a date picker view on my app however, when I select a date on the calendar view it updates the text to one day prior instead of the selected date. I'm assuming it has to do with the formatting function. I'm using Android Jetpack Compose and followed a tutorial from Medium that explains the implementation but its not working as expected. Thank you in advance.
#ExperimentalComposeApi
#Composable
fun DatePickerview() {
var datePicked: String? by remember {
mutableStateOf(null)
}
val updatedDate = { date: Long? ->
datePicked = DateFormater(date)
}
val activity = LocalContext.current as AppCompatActivity
Box(
modifier = Modifier
.fillMaxSize()
.wrapContentSize(Alignment.TopStart)
.padding(16.dp)
.border(3.dp, DarkerButtonBlue, RoundedCornerShape(10.dp))
.clickable {
showDatePicker(activity, updatedDate)
}
) {
ConstraintLayout(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
val (label, iconView) = createRefs()
Text(
text = datePicked ?: "Event Date",
color = Color.White,
fontSize = 20.sp,
modifier = Modifier
.fillMaxWidth()
.constrainAs(label) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(iconView.start)
width = Dimension.fillToConstraints
}
)
Icon(
imageVector = Icons.Default.DateRange,
contentDescription = null,
modifier = Modifier
.size(30.dp)
.constrainAs(iconView) {
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
tint = Color.DarkGray
)
}
}
}
fun DateFormater(milliseconds: Long?): String? {
milliseconds?.let {
val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.US)
val calendar: Calendar = Calendar.getInstance()
calendar.setTimeInMillis(it)
return formatter.format(calendar.getTime())
}
return null
}
fun showDatePicker(
activity: AppCompatActivity,
updateDate: (Long?) -> Unit
) {
val picker = MaterialDatePicker.Builder.datePicker().build()
picker.show(activity.supportFragmentManager, picker.toString())
picker.addOnPositiveButtonClickListener {
updateDate(it)
}
}
Most likely your problem is with your time zone, try specifying it:
fun DateFormater(milliseconds: Long?): String? {
milliseconds?.let {
val formatter = java.text.SimpleDateFormat("MM/dd/yyyy", Locale.US)
val calendar: Calendar = Calendar.getInstance()
formatter.timeZone = calendar.timeZone
calendar.timeInMillis = it
return formatter.format(calendar.time)
}
return null
}
Also a little off-topic. Using ConstraintLayout for such a simple layout is unnecessary. You can use Row with the weight modifier for your text: in this case the size of Icon will be calculated before the size of Text, see weight modifier documentation for details.
Row(
modifier = Modifier
.padding(16.dp)
) {
Text(
text = datePicked ?: "Event Date",
color = Color.White,
fontSize = 20.sp,
modifier = Modifier
.weight(1f)
)
Icon(
imageVector = Icons.Default.DateRange,
contentDescription = null,
tint = Color.DarkGray,
)
}

textAllCaps in jetpack compose

How do I achieve the same effect as textAllCaps in Jetpack Compose, I know that I can use toUpperCase method on the string itself to turn the string into uppercase. But I wonder is there a property that I can add to Text composable to visually turn the text into uppercase?
Text(
text = stringResource(id = R.string.app_name).toUpperCase(Locale.current)
)
There's not such property, but you can create it by yourself:
#Composable
fun CapsText(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
) {
Text(
text = text.uppercase(),
modifier = modifier,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines,
onTextLayout = onTextLayout,
style = style,
)
}
Text(
text = stringResource(id = R.string.app_name).uppercase()
)
You can just add .uppercase() on the stringResource.
currently I'm using compose 1.2.0-beta03 version.
.toUpperCase(Locale.current) is deprecated and replaced with .uppercase()
example usage as below :
Text(
text = ("any").uppercase()
)
This will render in UI as ANY
You can do this:
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters
)
You can always use capitalize function of String class. Alternatively, Text composable can also take Annotated String as an input, you can use toUpperCase function of AnnotatedString:
#Preview(showBackground = true)
#Composable
fun Sample() {
Text(text = upperCased("Hello"))
}
#Composable
fun upperCased(input: String): AnnotatedString {
return buildAnnotatedString {
append(input)
// You can also add styling here as below:
//
// withStyle(style = SpanStyle(color = Color.Blue)) {
// append("John")
// }
// append("Doe")
//
// withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
// append("W")
// }
// append("orld")
}.toUpperCase()
}
One benefit I see here is that you can avoid re-writing styles throughout the app.
Text(
stringResource(id = R.string.main_widget)**.toUpperCase(Locale.getDefault())**,
fontFamily = aeonikPro,
fontWeight = FontWeight.Medium,
color = ColorGraySecondary,
fontSize = 20.sp
)

Resources