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
)
Related
#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.
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")
}
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
}
)
}
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,
)
}
I'd start to use Dotnet.HighCharts controls to draw charts on my page in ASP.NET MVC app.
I used Google Charts, but they don't have enough functionality.
The task is to make charts with area ranges, step line and syncronized crosshair on multiple charts. Does DotNet.HighCharts do it?
By this time i did draw only area ranges.
If not, please give me a hint, which controls can do it.
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart())
.SetTitle(new Title { Text = "July temperatures" })
.SetXAxis(new XAxis { Type = AxisTypes.Datetime })
.SetYAxis(new YAxis { Title = new YAxisTitle { Text = string.Empty } })
.SetLegend(new Legend { Enabled = false })
.SetTooltip(new Tooltip
{
Crosshairs = new Crosshairs(true),
Shared = true,
ValueSuffix = "°C"
})
.SetLegend(new Legend())
.SetSeries(new[]
{
new Series
{
Name = "Temperature",
Data = ChartsData.TemperatureVariationAverages,
ZIndex = 1,
Type = ChartTypes.Line,
PlotOptionsLine = new PlotOptionsLine
{
Marker = new PlotOptionsLineMarker
{
FillColor = Color.White,
LineWidth = 2,
LineColor = Color.Black
}
}
},
new Series
{
Name = "Range",
Data = ChartsData.TemperatureVariationRanges,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Green,
FillOpacity = 0.1,
}
},
new Series
{
Name = "Range3",
Data = ChartsData.TemperatureVariationRanges1,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Red,
FillOpacity = 0.1,
}
},
new Series
{
Name = "Range2",
Data = ChartsData.TemperatureVariationRanges2,
Type = ChartTypes.Arearange,
ZIndex = 0,
PlotOptionsArearange = new PlotOptionsArearange
{
LineWidth = 0,
LinkedTo = ":previous",
Color = Color.Yellow,
FillOpacity = 0.1,
}
}
});