Jetpack compose: How to hide content if too big? - android-jetpack-compose

I've got a some dynamic content that can vary in size and below that is a circular image. The problem is that when the content becomes too big, the image overflows the content.
The ideal thing would be that if dynamic sized content is too big, the image should be hidden instead. Is it possible to hide the image (the box) if it will not fit?
Example code:
#Composable
fun ImageTest(modifier: Modifier = Modifier,
outlineColor: Color = Color.White,
outlineSize: Dp = 16.dp,
image: Int) {
Column(
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
.fillMaxSize()
) {
Text("Content that can be of different sizes", style = MaterialTheme.typography.h2, modifier = Modifier.height(550.dp).background(Color.Red))
// Circular image - HIDE THE BOX IF IT DOESN'T FIT
Box(
modifier = modifier
.background(color = outlineColor, shape = CircleShape)
.padding(outlineSize)
.aspectRatio(ratio = 1f)
) {
Image(
painter = painterResource(id = image),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxSize()
)
}
}
}

Replace image container Box with BoxWithConstraints. Then, inside BoxWithConstraintsScope you can check how much space is available for your view, and if you don't have enough - don't display it.
BoxWithConstraints(
modifier = modifier
.background(color = outlineColor, shape = CircleShape)
.padding(outlineSize)
.aspectRatio(ratio = 1f)
) {
if (maxHeight > 200.dp) {
Image(
painter = painterResource(id = image),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.fillMaxSize()
)
}
}
If you wanna hide box background too, move it inside if.
If you want add an animation, replace if (maxHeight > 200.dp) { with AnimatedVisibility(visible = maxHeight > 200.dp) {

Related

How to get rid of white space from a card jetpack compose

I am working on this design where I have a column that has text and image on top and I have this card view but I want to remove this white space. The card is white I just added the blue to show the white space showing. How can I remove the white space. I want the R.color.purple_700 to fill that space.
Here is my code
Column(
modifier = modifier
.fillMaxSize()
) {
Column(
modifier = modifier
.fillMaxWidth()
.background(colorResource(id = R.color.purple_700))
.weight(2.0f),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// Do I add the box here?
Image(
painter = painterResource(id = R.drawable.ic_launcher_background),
contentDescription = "Logo"
)
Text(
text = "Sign in to Continue",
color = (colorResource(id = R.color.white)),
fontSize = 28.sp,
modifier = Modifier.padding(8.dp)
)
}
Card(
shape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp),
modifier = modifier
.fillMaxWidth()
.weight(5.0f), elevation = 8.dp
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
.scrollable(scrollState, Orientation.Vertical),
horizontalAlignment = Alignment.CenterHorizontally
) {
// then some outlinedText
}
Just add the background modifier to the Card.
Card(
modifier = Modifier.background(colorResource(id = R.color.purple_700))
//....
)

How to make custom tab indicator to be a rounded bar in Jetpack Compose

The following picture shows what I want to achieve. I want the tab indicator to be a short rounded bar.
I looked up the implementation of TabRowDefaults.Indicator(), and just made my own one. I just tried to add the clip() modifier, but it didn't work. And I tried to change the order of the modifiers, but still no luck.
And here is my code implementation:
#Composable
fun TabLayout(
tabItems: List<String>,
content: #Composable () -> Unit
) {
var tabIndex by remember { mutableStateOf(0) }
Column {
ScrollableTabRow(
selectedTabIndex = tabIndex,
edgePadding = 0.dp,
backgroundColor = MaterialTheme.colors.background,
contentColor = Blue100,
indicator = { tabPositions ->
Box(
modifier = Modifier
.tabIndicatorOffset(tabPositions[tabIndex])
.height(4.dp)
.clip(RoundedCornerShape(8.dp)) // clip modifier not working
.padding(horizontal = 28.dp)
.background(color = AnkiBlue100)
)
},
divider = {},
) {
tabItems.forEachIndexed { index, item ->
Tab(
selected = tabIndex == index,
onClick = { tabIndex = index },
selectedContentColor = Blue100,
unselectedContentColor = Gray200,
text = {
Text(text = item, fontFamily = fontOutfit, fontSize = 18.sp)
}
)
}
}
Divider(
color = Gray50,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp)
)
content()
}
}
You applied Modifier.padding between Modifier.clip and Modifier.background, so the rounding is actually applied to the transparent padding. You need to move the padding in front of the clip, or specify the shape with the background:
.background(color = AnkiBlue100, shape = RoundedCornerShape(8.dp))
Read more about why the order of the modifiers matters in this answer

Jetpack Compose - Fit Text in a specific box

How can I fit a text, inside a specific Box / Container (i.e of Size 100.dp)
Is there a way to Fit a string inside a Box, in Compose?
Here is what I tried:
#Composable
fun playText() {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF242E38)),
contentAlignment = Alignment.Center
) {
Row(modifier = Modifier
.background(Color(0xFFEEEEEE))
.width(100.dp)
.height(100.dp)
) {
Text(
text = "FIT ME",
modifier = Modifier
.fillMaxSize()
.wrapContentSize(
Alignment.Center,
unbounded = true
)
.requiredSize(100.dp),
color = Color(0xFF242E38),
fontSize = 50.sp,
style = TextStyle.Default.copy(
background = Color(0xFFEAC43D)
)
)
}
}
}
#Preview(showBackground = true)
#Composable
fun show() {
playText()
}
Here is the current result:
Here is the expected result (which I achieved by decreasing the font size, just to demonstrate what is expected):

How to make card gradient in Jetpack compose?

#Composable fun Gradientcard() {
val horizontalGradientBrush = Brush.horizontalGradient(
colors = listOf(
Blue,
lightBlue
)
)
Card(modifier = modifier = Modifier
.background(brush = horizontalGradientBrush),shape = RoundedCornerShape(20.dp)){
Text(
text = "sub 1",
)
}
This method made background of card as gradient but not the card. Card color is still white.
Output
Instead of using modifier in Card try creating Box layout inside Card and add gradient code inside it.
Card(
modifier = Modifier
.fillMaxWidth()
.height(175.dp),
elevation = 4.dp,
shape = RoundedCornerShape(24.dp),
) {
Box(
Modifier
.background(
/* Your code*/ ) {
Text(
text = "Card Gradient Background",
)
}
}
Just cut that modifier from theText, and paste it in the Card
Card(modifier = ... /*Paste*/){
}

How do I set a shadow color for Jetpack Compose?

Sorry, I can hardly speak English.
machine translation:
How do I set a shadow color for Jetpack Compose?
I can set shadows, but they're ugly.
Jetpack Compose code:
Surface(
modifier = Modifier.width(160.dp).height(56.dp),
shape = CircleShape,
elevation = 2.dp,
) {
...
}
I want to create a shadow in the code below.
SwiftUI code:
ZStack {
...
}
.shadow(color: Color("button_shadow"), radius: 4, x: 0, y: 2)
.shadow(color: Color("button_shadow"), radius: 20, x: 0, y: 4)
Dark mode also requires a white shadow.
You want to be able to customize the color of the shadow.
Compose 1.2.0-alpha06 now supports shadow color attribute for the graphics layer modifier! ambientColor and spotColor can change the color of your shadow.
It's only useful with shapes though (CircleShape, RectangleShape, RoundedCornerShape, or your custom shape)
fun Modifier.shadow(
elevation: Dp,
shape: Shape = RectangleShape,
clip: Boolean = false,
elevation: Dp = 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
)
https://developer.android.com/jetpack/androidx/releases/compose-ui#1.2.0-alpha06
In my case for cycle I use this workaround:
#Composable
fun MyButton(){
Box(
modifier = Modifier
.size(64.dp)
.background(
brush = Brush.radialGradient(
colors = listOf(
Color.Yellow,
Color.Transparent
)
)
)
.padding(bottom = 4.dp),
contentAlignment = Alignment.Center
) {
Surface(
shape = CircleShape,
modifier = Modifier
.size(55.dp)
.background(Color.Transparent)
.clickable { }
) {
Box(
modifier = Modifier.padding()
.background(Color.Gray),
contentAlignment = Alignment.Center
) {
Icon(
modifier = Modifier.size(35.dp),
imageVector = Icons.Filled.Refresh,
contentDescription = "",
tint = Color.Yellow
)
}
}
}
}
there is the preview:
This is not possible at the moment but you can star the issue here: Link to Issue Tracker
The idea would be to have a modifier for the color, opacity, shape etc.
Well, this has recently changed and you can do it using Material 3 Jetpack Compose library. Just call shadow on modifier and set desired color.
Add dependency
implementation 'androidx.compose.material3:material3:1.0.0-alpha12'
implementation "androidx.compose.ui:1.2.0-beta02"
and add shadow modifier.
.shadow(
elevation = 8.dp,
ambientColor = primaryBlue,
spotColor = primaryBlue
)
sample code.
Image(
painter = painterResource(id = R.drawable.ic_capture_icon),
contentDescription = "capture",
modifier = Modifier
.padding(20.dp)
.background(shape = RoundedCornerShape(15.dp), color = primaryBlue)
.size(60.dp)
.shadow(
elevation = 8.dp,
ambientColor = primaryBlue,
spotColor = primaryBlue
)
.align(Alignment.BottomEnd)
.padding(12.dp)
.clickable {
context.startActivity(Intent(context, GeoSpatialActivity::class.java))
},
colorFilter = ColorFilter.tint(color = Color.White)
)
You can use the code below to add a colorful shadow to your Modifier:
fun Modifier.advanceShadow(
color: Color = Color.Black,
borderRadius: Dp = 16.dp,
blurRadius: Dp = 16.dp,
offsetY: Dp = 0.dp,
offsetX: Dp = 0.dp,
spread: Float = 1f,
) = drawBehind {
this.drawIntoCanvas {
val paint = Paint()
val frameworkPaint = paint.asFrameworkPaint()
val spreadPixel = spread.dp.toPx()
val leftPixel = (0f - spreadPixel) + offsetX.toPx()
val topPixel = (0f - spreadPixel) + offsetY.toPx()
val rightPixel = (this.size.width)
val bottomPixel = (this.size.height + spreadPixel)
if (blurRadius != 0.dp) {
/*
The feature maskFilter used below to apply the blur effect only works
with hardware acceleration disabled.
*/
frameworkPaint.maskFilter =
(BlurMaskFilter(blurRadius.toPx(), BlurMaskFilter.Blur.NORMAL))
}
frameworkPaint.color = color.toArgb()
it.drawRoundRect(
left = leftPixel,
top = topPixel,
right = rightPixel,
bottom = bottomPixel,
radiusX = borderRadius.toPx(),
radiusY = borderRadius.toPx(),
paint
)
}
}
the link in the comment of #EpicPandaForce uses converts color to int using android.graphics.Color.Argb(Long) which required Api Level >= 26. I found another link in that gist comment in which function argb is used and it is in API level 1 added.
https://gist.github.com/arthurgonzaga/598267f570e38425fc52f97b30e0619d

Resources