Unable to reduce the huge padding in OutlinedButton. Tried contentPadding, modifier padding, etc. Cannot reduce padding for text "apple". Any idea? Should I use any other type of compose component for this?
OutlinedButton(
onClick = {},
border = BorderStroke(1.dp, Color.White),
shape = RoundedCornerShape(12.dp),
contentPadding = PaddingValues(0.dp),
modifier = Modifier
.background(bgColor)
.height(24.dp)
.padding(all = 0.dp),
colors = ButtonDefaults.outlinedButtonColors(backgroundColor = bgColor)) {
Text("apple",
color = Color.White,
style = MaterialTheme.typography.body2,
modifier = Modifier.height(10.dp).padding(vertical = 0.dp), //.background(bgColor),
)
}
Updated after #liveAnyway's answer (thanks!) which appeared to help. After that I removed height from OutlinedButton too - ideally I wanted it like "wrap-content". Once I made that change, I still see the padding. Bottomline I don't want any absolute height specified so that it can work with different font size from system settings.
Row(modifier = Modifier.padding(vertical = 12.dp)) {
OutlinedButton(
onClick = {},
border = BorderStroke(1.dp, Color.White),
shape = RoundedCornerShape(18.dp),
contentPadding = PaddingValues(0.dp),
modifier = Modifier
.background(bgColor)
.padding(all = 0.dp),
colors = ButtonDefaults.outlinedButtonColors(backgroundColor = bgColor)
) {
Text("apple",
color = Color.White,
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(vertical = 0.dp),
)
}
}
Button has default min size modifier. This is done according to Material guidelines, so that the button is easy to hit. If the control size is too small, the user may have problems hitting it, take this into account when changing this parameter.
You can override it by applying defaultMinSize modifier. The 0.dp will be ignored, but starting from 1.dp you will get the desired result:
OutlinedButton(
onClick = { /*TODO*/ },
contentPadding = PaddingValues(),
modifier = Modifier
.defaultMinSize(minWidth = 1.dp, minHeight = 1.dp)
) {
Text(
"Apple",
)
}
Alternatively, you can design your own button without these restrictions:
Surface(
onClick = {
},
shape = MaterialTheme.shapes.small,
color = bgColor,
contentColor = MaterialTheme.colors.primary,
border = ButtonDefaults.outlinedBorder,
role = Role.Button,
) {
Text(
"Apple",
)
}
You have to change the minHeight (default size are MinWidth = 64.dp and MinHeight = 36.dp) and remove the contentPadding with contentPadding = PaddingValues(0.dp):
OutlinedButton(
onClick = {},
border = BorderStroke(1.dp, Color.White),
shape = RoundedCornerShape(12.dp),
contentPadding = PaddingValues(0.dp),
modifier = Modifier.defaultMinSize(
minWidth = ButtonDefaults.MinWidth,
minHeight = 10.dp
)
) {
Text(
"apple",
style = MaterialTheme.typography.body2
)
}
Related
I am trying to display a Button with rounded corners and a 50% transparent background. My current attempt looks like this:
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.Yellow
) {
Column(modifier = Modifier.padding(10.dp)) {
Button(
modifier = Modifier
.clip(CircleShape),
onClick = { },
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White.copy(alpha = 0.5f))
) {
Text(
text = "My Button",
textAlign = TextAlign.Center
)
}
}
}
}
The result is not very pretty:
It looks like the issue is with with the shading, but I'm not sure how to remove it and just show the same color within the whole shape.
Turns out the shadow will disappear when the elevation is removed.
Button(
modifier = Modifier
.clip(CircleShape),
onClick = { },
elevation = null,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.White.copy(alpha = 0.5f))
) { ... }
Button is just a Surface wrapping the content that you provide. You could check the source. So, I just tweaked it a little
#Composable
fun HollowButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: #Composable RowScope.() -> Unit
) {
val contentColor by colors.contentColor(enabled)
Surface(
modifier = modifier,
shape = shape,
color = colors.backgroundColor(enabled).value.copy(0.5f), //Basically I refactored the alpha modification to here
contentColor = contentColor.copy(alpha = 1f),
border = border,
elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = rememberRipple()
) {
CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(
value = MaterialTheme.typography.button
) {
Row(
Modifier
.defaultMinSize(
minWidth = ButtonDefaults.MinWidth,
minHeight = ButtonDefaults.MinHeight
)
.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
}
}
Works like a charm.
I have two layers in my Compose layout: One for the actual content and the one above is a Box-wrapped OutlinedTextField for search queries.
Here's the sample code:
// Placeholder for layout content
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(id = R.string.lorem_ipsum),
color = Color.Gray
)
}
// Overlaying Box with OutlinedTextField
Box(modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 64.dp)
) {
OutlinedTextField(
value = viewModel.query.value,
onValueChange = { viewModel.updateQuery(it) },
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding(),
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
autoCorrect = false,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.None
),
shape = CircleShape,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White
),
placeholder = { Text(stringResource(id = R.string.search_input_placeholder)) },
maxLines = 1,
singleLine = true
)
}
Even though I'm setting
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White
)
in the OutlinedTextField, the background stays transparent as you can see in the following screenshot:
Adding a background color on the OutlinedTextField's modifier is giving the whole row a rectangled background, which is also not the desired result.
The OutlinedTextField with it's CircleShape should only have a background inside of the shape. How can I achieve that?
I'm using Jetpack Compose version 1.0.4.
Reason
Unfortunately, in version 1.0.4, OutlinedTextField ignores the backgroundColor even if you specify it, so you can remove the colors parameter.
Support for it will be added in 1.1.0:
https://android-review.googlesource.com/c/platform/frameworks/support/+/1741240
It's already present in 1.1.0-alpha06 so you can play with it if you want. Your original code should produce desired outcome on that version.
Solution
To achieve what you want (before 1.1.0 is released) you can simply add a background modifier with the same shape:
.background(Color.White, CircleShape)
Since the order of modifiers is important, you should add it after you apply all the paddings (navigationBarsWithImePadding in your case). Like that:
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding()
.background(Color.White, CircleShape),
Note: Also be aware that you cannot use the label parameter with this approach, because the TextField with label will be higher than just the outline shape and these two shaped wouldn't match in size anymore.
Result
Entire code:
// Placeholder for layout content
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(id = R.string.lorem_ipsum),
color = Color.Gray
)
}
// Overlaying Box with OutlinedTextField
Box(modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 64.dp)
) {
OutlinedTextField(
value = viewModel.query.value,
onValueChange = { viewModel.updateQuery(it) },
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding()
.background(Color.White, CircleShape),
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
autoCorrect = false,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.None
),
shape = CircleShape,
placeholder = { Text(stringResource(id = R.string.search_input_placeholder)) },
maxLines = 1,
singleLine = true
)
}
How the final result looks like:
I am trying to remove padding from TextButton but it wont work.
TextButton(
onClick = {},
modifier = Modifier.padding(0.dp)
) {
Text(
" ${getString(R.string.terms_and_conditions)}",
color = MaterialTheme.colors.primary,
fontFamily = FontFamily(Font(R.font.poppins_regular)),
fontSize = 10.sp,
)
}
I have tried setting the height and size in Modifier property as well but the padding is still present
Wrap the TextButton with CompositionLocalProvider to override the value of LocalMinimumTouchTargetEnforcement. This will only remove the extra margin but will not modify the defaultMinSize which is hardcoded.
CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false,
) {
TextButton(
onClick = {},
contentPadding = PaddingValues(),
) {
Text(
"Button",
color = MaterialTheme.colors.primary,
fontSize = 10.sp,
)
}
}
You cannot reduce padding with the padding modifier: it always adds an extra padding on top of the existing padding. See this reply for more details about the order of modifiers.
You can reduce TextButton padding with contentPadding argument, by specifying PaddingValues(0.dp), but this will not fully remove the padding.
If you need fully remove the padding, you can use the clickable modifier instead:
Text(
"getString(R.string.terms_and_conditions",
color = MaterialTheme.colors.primary,
fontFamily = FontFamily(Font(R.font.neris_semi_bold)),
fontSize = 10.sp,
modifier = Modifier
.clickable {
// onClick()
}
)
If you want to change the color of the ripple, as is done in TextButton, you can do it as follows:
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(color = MaterialTheme.colors.primary),
) {
}
You can achieve it changing the contentPadding and applying a fixed size:
TextButton(
onClick = {},
contentPadding = PaddingValues(0.dp),
modifier = Modifier.height(20.dp).width(40.dp)
) {
Text(
"Button",
color = MaterialTheme.colors.primary,
fontSize = 10.sp,
)
}
If you come across unwanted margins. When you use onclick in any Button function, it sets propagateMinConstraints = true inside the view's surface - this will apply to unwanted margins. Example how solve this problem:
#Composable
fun ButtonWithoutOuterPadding(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = RectangleShape,
elevation: Dp = 0.dp,
color: Color = Color.Transparent,
border: BorderStroke? = null,
contentAlignment: Alignment = Alignment.Center,
content: #Composable () -> Unit
) {
Box(
modifier
.shadow(elevation, shape, clip = false)
.then(if (border != null) Modifier.border(border, shape) else Modifier)
.background(
color = color,
shape = shape
)
.clip(shape)
.then(
Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = LocalIndication.current,
enabled = true,
onClickLabel = null,
role = null,
onClick = onClick
)
),
contentAlignment = contentAlignment,
propagateMinConstraints = false
) {
content()
}
}
I'm new to Jetpack compose, I have create a composable like this.
Column(
Modifier.clickable(onClick = onclick)
.fillMaxWidth().background(pastelGray)
.padding(16.dp)
) {
Card(backgroundColor = Color.Cyan) {
// Image(asset = vectorResource(id = R.drawable.ic_coupon_back), modifier = Modifier.fillMaxWidth())
Column(modifier = Modifier.padding(8.dp)) {
Text(text = coupon.couponTitle, color = Color.Red, fontSize = 20.sp)
Text(text = coupon.couponSubTitle, color = Color.Black, fontSize = 13.sp)
Text(text = coupon.couponDateTitle, color = Color.Gray, fontSize = 11.sp)
}
}
}
When I add that commented image I got this error:
Surface can have only one direct measurable child!
I could not find the reason till now.
Because Card() composable used in your code uses Surface under the hood:
#Composable
fun Card(
modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium,
backgroundColor: Color = MaterialTheme.colors.surface,
contentColor: Color = contentColorFor(backgroundColor),
border: BorderStroke? = null,
elevation: Dp = 1.dp,
content: #Composable () -> Unit
) {
Surface(
modifier = modifier,
shape = shape,
color = backgroundColor,
contentColor = contentColor,
elevation = elevation,
border = border,
content = content
)
}
source: Official Card Implementation code
And Surface is a kind like ScrollView doesn't accept more than one direct child. So you need to wrap your code inside Card() into a single parent that is a direct child of Card or in other words direct child of Surface, example:
Card(backgroundColor = Color.Cyan) {
CardContent()
}
private fun CardContent() {
Column() {
// Image(asset = vectorResource(id = R.drawable.ic_coupon_back), modifier = Modifier.fillMaxWidth())
Column(modifier = Modifier.padding(8.dp)) {
Text(text = coupon.couponTitle, color = Color.Red, fontSize = 20.sp)
Text(text = coupon.couponSubTitle, color = Color.Black, fontSize = 13.sp)
Text(text = coupon.couponDateTitle, color = Color.Gray, fontSize = 11.sp)
}
}
}
}
I have a problem with jetpack compose elevation render. I'm trying to add elevation on Surface but my UI seems to with clipped shadow. Also, how can I add a colorful shadow on my Surface?
See the below on the screenshot
#Composable
fun DiscoverItem() {
Surface(
contentColor = Color(0xFFFFFFFF),
modifier = Modifier.preferredWidthIn(min = 145.dp).preferredHeight(56.dp),
shape = CircleShape,
elevation = 8.dp,
) {
Row(
modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Surface(
modifier = Modifier.preferredSize(40.dp),
shape = CircleShape,
color = Color(0xFFFFC3D8)
) {
Image(
imageResource(R.drawable.pin_icon),
modifier = Modifier.size(width = 18.dp, height = 24.dp),
contentScale = ContentScale.Fit
)
}
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(
"YOUR AREA",
style = MaterialTheme.typography.body2,
color = Color(0xFFFC1055)
)
}
}
}
#Composable
#Preview
fun DiscoverItemPreview() {
DiscoverItem()
}
You don't have enough content on bottom of your layout. You can add spacer to view your shadow.
#Composable
#Preview
fun DiscoverItemPreview() {
Column{
DiscoverItem()
Spacer(modifier = Modifier.height(20.dp))
}
}
And about colorful shadow, compose min sdk is Android Lollpop and skia version for lollipop doesnot supports colorful shadow/elevation. Leland Richardson had talked about this issue in his youtube video on Compose dogfooding. here
I use surface to wrap the shadowed card and it gives me expected result.
Surface(
elevation = 4.dp,
color = MaterialTheme.colors.surface,
shape = Shapes.medium,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(
animationSpec = tween(
durationMillis = 300,
easing = LinearOutSlowInEasing
)
),
elevation = 8.dp,
shape = Shapes.medium,
onClick = {
isExpanded = !isExpanded
}
) {}}
enter image description here