Jetpack Compose Change Slider Thumb Size - android

Is there any way to change slider thumb size? I think for now we can only manipulate colors
var sliderPosition by remember { mutableStateOf(0f) }
Text(text = sliderPosition.toString())
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..100f,
onValueChangeFinished = {
// launch some business logic update with the state you hold
// viewModel.updateSelectedSliderValue(sliderPosition)
},
steps = 5,
colors = SliderDefaults.colors(
thumbColor = MaterialTheme.colors.secondary,
activeTrackColor = MaterialTheme.colors.secondary
)
)

No, this size cannot be modified. The only thing you can do is copy the entire Slider.kt file into your project and modify it.
It is a good idea to give the new view a different name to avoid misunderstandings in the future.
You should change ThumbRadiusconstant, or make it a variable if you need different sizes in your application.

With M3 androidx.compose.material3.Slider you can use the thumb attribute to customize the size.
Something like:
var sliderPosition by remember { mutableStateOf(0f) }
Column {
Text(text = sliderPosition.toString())
Slider(
modifier = Modifier.semantics { contentDescription = "Localized Description" },
value = sliderPosition,
onValueChange = { sliderPosition = it },
valueRange = 0f..5f,
steps = 4,
interactionSource = interactionSource,
onValueChangeFinished = {
// launch some business logic update with the state you hold
},
thumb = {
SliderDefaults.Thumb( //androidx.compose.material3.SliderDefaults
interactionSource = interactionSource,
thumbSize = DpSize(40.dp,40.dp)
)
},
)
}
Note: it requires for material3 at least the version 1.0.0-beta03

I've created a library for easy customization of Slider, since Slider from Material package is not flexible.
https://github.com/krottv/compose-sliders. Below is the code example of how to use it to make thumb size smaller:
var stateSlider by remember { mutableStateOf(0.5f) }
SliderValueHorizontal(
stateSlider, { stateSlider = it },
modifier = Modifier
.fillMaxWidth(),
// desired size of Slider's thumb
thumbSize = DpSize(8.dp, 8.dp)
)
Also you can specify custom composables for thumb and track.

Yes, but only wrapping it with AndroidView and wait for the better future, when Google team release another update in Material lib.
Here is an example
AndroidView(
modifier = Modifier...//,
factory = { context ->
Slider(
ContextThemeWrapper(context, context.theme)
).apply {
// set listeners
it.addOnSliderTouchListener(object : SliderView.OnSliderTouchListener {
#SuppressLint("RestrictedApi")
override fun onStartTrackingTouch(slider: Slider) = Unit
#SuppressLint("RestrictedApi")
override fun onStopTrackingTouch(slider: Slider) {
onValueChangeFinished.invoke()
}
})
it.addOnChangeListener { _, value, _ ->
onValueChanged.invoke(value)
}
// your thumb customization
// your track customization
}
}, update = {
// set value
it.value = currentValue
})
Should be placed inside #Composable
AndroidView in Compose
Slider in Material

Related

How to remove Surface padding in jetpack compose

In LazyColumn when we use LazyListScope.items with Surface. Inside multiple items there is extra padding on TOP and BOTTOM. I want to remove this padding. I am using Surface component of Material 3. BOM version is compose_bom = "2022.11.00".
Please don't suggest any alpha or beta version fix. If Material 3 stable api don't have solution, then please suggest normal Surface Material.
PreviewCreateListView
#Preview(showBackground = true)
#Composable
fun PreviewCreateListView() {
CreateListView()
}
CreateListView
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun CreateListView() {
val itemList = listOf(1, 2, 3)
LazyColumn(
contentPadding = PaddingValues(16.dp),
) {
items(itemList) { item ->
Surface(
onClick = { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
}
}
Output
The M3 Surface with the onClick parameter has a minimum touch target size (48.dp) for accessibility. It will include extra space outside the component to ensure that they are accessible.
You can override this behaviour applying false to the LocalMinimumInteractiveComponentEnforcement. If it is set to false there will be no extra space.
Something like:
CompositionLocalProvider(
LocalMinimumInteractiveComponentEnforcement provides false) {
Surface(
onClick = { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
Note: LocalMinimumInteractiveComponentEnforcement requires at least
M2 1.4.0-alpha04 and M3 1.1.0-alpha04. Before you can use LocalMinimumTouchTargetEnforcement in the same way.
The Surface variant that you use, with a onClick parameter, enforces a minimum height for accessibility purposes, see this at line 221
If you want to remove the space, use the variant without the onClick argument and use a Modifier.clickable instead
#Composable
fun CreateListView() {
val itemList = listOf(1, 2, 3)
LazyColumn(
contentPadding = PaddingValues(16.dp),
) {
items(itemList) { item ->
Surface(
modifier = Modifier.clickable { },
color = Color.Blue
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "$item",
)
}
}
}
}

How can I animate between 0 and wrap content values ​using compose

I'm trying to make a swipe to reveal component using compose, but I want the width of the card that will appear after the swipe to grow to the size of the wrap content without using it, but I don't understand how to calculate the wrap content size.
var width by remember {
mutableStateOf(0.dp)
}
val lowerTransition = updateTransition(transitionState, "lowerCardTransition")
val lowerOffsetTransition by lowerTransition.animateFloat(
label = "lowerCardOffsetTransition",
transitionSpec = { tween(durationMillis = ANIMATION_DURATION) },
targetValueByState = { if (isRevealed) width.value else 0f },
)
How do I equate the width value used here to the wrap content value?
I'm trying to make the resulting delete button appear all without using a constant value
Try using AnimatedVisibility. For demo purpose I used OnClick, replace it with OnSwipe.
#Preview
#Composable
fun AnimateVisibility2() {
var visible by remember {
mutableStateOf(false)
}
Row(
modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.Center
) {
AnimatedVisibility(
visible = visible, enter = expandHorizontally(), exit = shrinkHorizontally()
) {
IconButton(onClick = { /*TODO*/ }) {
Icon(Icons.Default.Phone, contentDescription = null)
}
}
Button(onClick = { visible = !visible }, Modifier.weight(1f)) {
Text("Click Me")
}
}
}

TopAppBar and padding (Jetpack Compose)

I have a slightly different expectation for padding to work. How can this problem be solved? I see this only at TopAppBar.
CenterAlignedTopAppBar(
title = { Text(title) },
modifier = Modifier.statusBarsPadding(), // or padding(top = 24.dp)
actions = {
if (isSync) {
IconButton(
onClick = { },
enabled = false,
content = {
Icon(
painter = painterResource(R.drawable.ic_outline_cloud_download_24),
contentDescription = title,
tint = Color.DarkGray.copy(alpha = alpha)
)
}
)
}
},
scrollBehavior = scrollBehavior
)
UPD
For example, here it works as it should -> link
I made it myself based on the source code. Not quite universal, but just right for me. I will not give the full code, it is in the source code. I will give only the place where it is necessary to add.
#Composable
private fun TopAppBarLayout(...) {
Layout(
...,
modifier = modifier.statusBarsPadding()
) {
...
}
}
The rest of the code is identical to the original.
UPDATE 21
Now everything works out of the box.

Dynamic row width compose

I need to create a searchbar that looks like this (strictly compose):
Now i managed to get the one without text working, but i cannot get the cancel text to show up without bugs.
For example when using constraint row and some paddings i get effect like this
link to the working code:
https://gist.github.com/piotrsedlak/d71da26299946ef6fc5125042e04a154
I also tried working with animateContentSize but that didnt really help.
I think this can be easily achieved using weight modifier. Conditionally adjust the weights and you'll get the desired effect. Here's a snippet for the same:
#Composable
fun DynamicToolbar() {
var text by remember { mutableStateOf(TextFieldValue()) }
val fieldWeight = if (text.text.isNotBlank()) 0.8f else 1f
Row(modifier = Modifier.fillMaxWidth()
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
leadingIcon = { Icon(Icons.Default.Search, null, tint = Color.DarkGray) },
trailingIcon = {
if (text.text.isNotBlank()) {
Icon(
Icons.Default.Close,
null,
tint = Color.LightGray,
modifier = Modifier.clickable { text = text.copy("") }
)
}
},
modifier = Modifier
.weight(fieldWeight)
.alignBy(FirstBaseline)
)
if (text.text.isNotBlank()) {
TextButton(
onClick = { },
modifier = Modifier
.fillMaxWidth()
.weight(1 - fieldWeight)
.alignBy(FirstBaseline)
) {
Text("Cancel")
}
}
}
}
I'm using Compose 1.0.0-alpha11
PS: I fixed the baseline alignment problem as well (credits). Hope that helps.

Using Custom Views with Jetpack Compose

Let's suppose I'm using some library that's intended to provide some UI Widgets.
Let's say this library provides a Button Widget called FancyButton.
In the other hand, I have a new project created with Android Studio 4 that allows me to create a new project with an Empty Compose Activity.
The question is:
How should I add this FancyButton to the view stack? Is it possible? Or with Jetpack Compose I can only use components that had been developed specifically for Jetpack Compose. In this case, AFAIK I could only use Android standars components (Text, MaterialTheme, etc).
If I try to use something like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Greeting("Android")
FancyButton(context, "Some text")
}
}
}
then I get this error:
e: Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath.
Currently (as of 0.1.0-dev04), there is not a good solution to this. In the future, you'll be able to simply call it as FancyButton("Some text") (no context needed).
You can see a demo of what it will look like in the Compose code here.
Update in alpha 06
It is possible to import Android View instances in a composable.
Use ContextAmbient.current as the context parameter for the View.
Column(modifier = Modifier.padding(16.dp)) {
// CustomView using Object
MyCustomView(context = ContextAmbient.current)
// If the state updates
AndroidView(viewBlock = ::CustomView, modifier = modifier) { customView ->
// Modify the custom view
}
// Using xml resource
AndroidView(resId = R.layout.view_demo)
}
You can wrap your custom view within the AndroidView composable:
#Composable
fun RegularTextView() {
AndroidView(
factory = { context ->
TextView(context).apply {
text = "RegularTextView"
textSize = 34.dp.value
}
},
)
}
And here is how to update your custom view during a recomposition, by using the update parameter:
#Composable
fun RegularTextView() {
var string by remember {
mutableStateOf("RegularTextView")
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
AndroidView(
factory = { context ->
TextView(context).apply {
textSize = 34.dp.value
}
},
update = { textView ->
textView.text = string
}
)
Spacer(modifier = Modifier.height(8.dp))
Button(
onClick = {
string = "Button clicked"
},
) {
Text(text = "Update text")
}
}
}
#Composable
fun ButtonType1(text: String, onClick: () -> Unit)
{
Button (
modifier=Modifier.fillMaxWidth().height(50.dp),
onClick = onClick,
shape = RoundedCornerShape(5.dp),
border = BorderStroke(3.dp, colorResource(id = R.color.colorPrimaryDark)),
colors = ButtonDefaults.buttonColors(contentColor = Color.White, backgroundColor = colorResource(id = R.color.colorPrimaryDark))
)
{
Text(text = text , color = colorResource(id = R.color.white),
fontFamily = montserrat,
fontWeight = FontWeight.Normal,
fontSize = 15.sp
)
}
}

Categories

Resources