Android Compose Shadow - android

Is Android Jetpack Compose shadow modifier supposed to look like this?
I'm so confused. I've written a few components and I'm testing the shadow modifier that I believe was introduced in compose-1.2.0-alpha. I'm now using 1.2.1. My component is written as this.
fun Labels() {
Label(
modifier = Modifier.shadow(
elevation = 1.dp,
shape = RoundedCornerShape(4.dp),
ambientColor = Color.Blue,
spotColor = Color.Blue
),
text = field.name,
style = typographies.tagDefault
)
}
Label is a mirror copy of Text for my own reasons, but that means it boils down to::
fun Label(...) {
BasicText(
text,
modifier,
mergedStyle,
onTextLayout,
overflow,
softWrap,
maxLines,
)
}
So in the grand scheme and to my understanding the shadow effect is ultimately being applied to the BasicText and nothing else. Which looks like the case in the image, but why is it so thick? Why isn't it more like a border the same as box-shadow in CSS? How can I make it look like it should with similarities to box-shadow in CSS? I've tried a few things like moving the modifier to higher component pieces and messing with the elevation. But all that has done is made the shadow a little hazy and maybe slightly thicker. Also if I change the shape to something like RoundedCornerShape(percent = 50) it nearly fills in the whole background with this blue color which is definitely not intended.

Related

Compose Card always overdrawn

Issue
Compose card surface shows always overdrawn. However, it's not the case if we use old style CardView in xml.
From here it's always recommended to reduce overdrawing of any view to make it more towards green, blue.
Just this following code will produce some output like this, which means it's overdrawn 3 or 4 times.
Card(
elevation = CardDefaults.cardElevation(defaultElevation = 10.dp),
modifier = modifier.fillMaxWidth().padding(vertical = 10.dp)
) {
Column(
modifier = Modifier
.padding(all = 16.dp)
) {
Text("randomText")
}
}
I tried to look into NowInAndroid sample application but even that produces all red output when debugged to show overdrawn areas.
Question
Is the Debug GPU Overdraw option in developer settings giving right information?
Can we really avoid this overdraw? If so, how?

Wrap Row components

I am trying to figure out how to figure out how to wrap my components in Jetpack Compose for narrow screens, e.g. Samsung fold.
For example:
Box(modifier = Modifier.fillMaxWidth()){
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Image(...)
Spacer(...)
Image(...)
Spacer(...)
SomeBadgeWithText(...)
}
}
On the narrow Samsung device, the last Badge gets squashed and text is cut off. I want it to just wrap to the next line. Is that possible?
AFAIK Wrapping content like you want is not a native compose feature. However Accompanist, a set of compose libraries developed by Google, offers Flow Layout which should suit your use-case.

Prevent shadow clipping without adding content padding in Jetpack Compose

This question notes that in order to not clip the shadows on a LazyRow/LazyColumn in Jetpack Compose you need to add ContentPadding. However, I want to do the equivalent of "clipToPadding=false" without adding additional padding (the padding should be 0.dp). Is this possible? Or do you have to have some sort of 1.dp padding around the object?
Ex:
LazyRow(
state = listState,
flingBehavior = flingBehavior,
contentPadding = PaddingValues(all = 0.dp)
)
See clipping shadows on the lefthand edge:

Material icon size adjustment in Jetpack Compose?

Jetpack compose provides a nice Icon() object to display icons that accepts a vector asset. Typically, you are able to set the size via a modifier:
Icon(Icons.Filled.PersonPin, Modifier.preferredSize(64.dp))
My problem is I cannot seem to affect the size of the displayed icon when I am using a provided system vector asset (ie, Icons.Filled. or Icons.Default. etc). When I use my own asset, things work as expected. Using the system assets the modifier only increases the UI footprint of the enclosing "box" while the icon stays tiny within:
Applying the modifier using 'then' results in the same behavior:
Icon(Icons.Filled.PersonPin,Modifier.then(Modifier.preferredSize(128.dp)))
Is there something about the native icons? I assumed being vector assets they should be able to resize as well.
With 1.0.x just use the Modifier.size(xx.dp)
Icon(Icons.Filled.Person,
"contentDescription",
modifier = Modifier.size(128.dp))
Internally material icon size is 24.dp
// All Material icons (currently) are 24dp by 24dp, with a viewport size of 24 by 24.
#PublishedApi
internal const val MaterialIconDimension = 24f
And using the size in modifier it's not working, So we can change the icon by copying the icon and change the default height and width.
Icon(Icons.Filled.Person.copy(defaultHeight = 128.dp, defaultWidth = 128.dp))
NOTE: This is not an official recommendation to set the icon size,
Just a hack way to change the icon size.
The accepted answer longer works in 1.0.0-alpha11. This is the associated bug report. As per the bug report comments, the new way of doing this from alpha12 on would be:
Icon(Icons.Filled.Person, modifier = Modifier.size(128.dp))
What works for me is to use Modifier.fillMaxSize(...)), e.g.
Icon(Icons.Filled.Person, contentDescription = "Person", modifier = Modifier.fillMaxSize(0.5F))
Icon(Icons.Filled.Person, contentDescription = "Person", modifier = Modifier.fillMaxSize(0.75F))
Icon(Icons.Filled.Person, contentDescription = "Person", modifier = Modifier.fillMaxSize(1.0F))
To make the answer above more accesible, define some extension functions:
fun VectorAsset.resize(size: Int) = this.resize(size.dp)
fun VectorAsset.resize(size: Dp) = this.resize(size, size)
fun VectorAsset.resize(width: Int, height: Int) = this.resize(width.dp, height.dp)
fun VectorAsset.resize(width: Dp, height: Dp) =
this.copy(defaultWidth = width, defaultHeight = height)

How to add Margin in Jetpack Compose?

How exactly can you add Margin in Jetpack Compose?
I can see that there is a Modifier for padding with Modifier.padding(...) but I can't seem to find one for margins or am I blind?
Someone guide me please.
Thank you very much.
You can consider padding and margin as the same thing (imagine it as "spacing"). A padding can be applied twice (or more) in the same composable and achieve the similar behavior you would get with margin+padding. For example:
val shape = CircleShape
Text(
text = "Text 1",
style = TextStyle(
color = Color.White,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center),
modifier = Modifier.fillMaxWidth()
.padding(16.dp)
.border(2.dp, MaterialTheme.colors.secondary, shape)
.background(MaterialTheme.colors.primary, shape)
.padding(16.dp)
)
Will result on this:
As you can see, the first padding is adding a space between the component and its border. Then the background and border are defined. Finally, a new padding is set to add space between the border and the text.
Thinking in terms of padding and margin you refer to the so-called box model that we are used to. There's no a box model in Compose but a sequence of modifiers which is applied to a given composable. The trick is that you can apply the same modifier like padding or border multiple times and the order of these matters, for example:
#Composable
fun PaddingExample() {
Text(
text = "Hello World!",
color = Color.White,
modifier = Modifier
.padding(8.dp) // margin
.border(2.dp, Color.White) // outer border
.padding(8.dp) // space between the borders
.border(2.dp, Color.Green) // inner border
.padding(8.dp) // padding
)
}
As the result you'll get this composable:
This design is well explained in the Modifiers documentation:
Note: The explicit order helps you to reason about how different modifiers will interact. Compare this to the view-based system where you had to learn the box model, that margins applied "outside" the element but padding "inside" it, and a background element would be sized accordingly. The modifier design makes this kind of behavior explicit and predictable, and gives you more control to achieve the exact behavior you want.
You can also use Spacer:
Spacer(modifier = Modifier.width(10.dp))
It represents an empty space layout, whose size can be defined using Modifier.width, Modifier.height and Modifier.size modifiers.
Suppose you want to add margin between 2 composables, then you can achieve it as
Text(
text = stringResource(id = R.string.share_your_posters),
fontSize = 16.sp,
color = Color.Black
)
Spacer(modifier = Modifier.width(10.dp))
Image(painter = painterResource(id = R.drawable.ic_starts), contentDescription = null)
The margin is different than padding, margin is the space outside the widget, where padding is the distance inside the widget, in old XML you could have decided explicitly which one to use, however the new compose way is different.
How compose treat paddings and margins?
There is an object which can be set as Parameter to the composable called Modifier, you can use this to do both margins and paddings.
Example of Padding:
Text(
text = "Test",
modifier = Modifier
.padding(16.dp)
.clickable { }
)
Example of Margin
Text(
text = "Test",
modifier = Modifier
.clickable { }
.padding(16.dp)
)
As you can see the order makes a difference here in compose, all the modifiers are implemented by order.
So from what I can understand after reading the documentation there is no margin modifier as such as the API designer felt it is redundant to give something different name which essentially does the same thing.
So let's say you want to apply a margin of 8dp before colouring your container with yellow background and you want the container with a padding of 4dp for the content.
Column(modifier = Modifier.padding(all = 8.dp)
.background(color = Color.Yellow)
.padding(all=4.dp)) {
Text(text = "Android")
...
}
Here in the above example you can see that I have applied the padding first and after that I have added background colour to the container and finally the last padding. And here's how it looks. Just like we intended.
I was also looking for something which should give me a direct option to set margin on a View like TextView. But unfortunately we don't have margin support in Jetpack compose. But the good news is we can still achieve it by using layout container like Box, which allows us to add views like TextView, ImageView etc.
So you can add margin to any of the child(TextView) by using padding modifier to the parent(Box).
Here is the code:
Box(Modifier.padding(10.dp)) {
Surface(color = Color.LightGray) {
Text(text = "Hello $text!", color = Color.Blue,
modifier = Modifier.padding(16.dp))
}
}
And the result is:
Here I have given 10.dp padding to the box.
Hope it is useful.
You can achieve the same effect as margin with putting your content, that has padding, inside a different composable like Box and make outer composable clickable. With this approach, inner padded areas will be included in clickable content.
You can achieve a margin effect by using nested Surface elements with padding
e.g.
#Composable
fun MainScreen() {
Surface(color=Color.Yellow, modifier=Modifier.padding(10.dp)){
Surface(color=Color.Magenta, modifier=Modifier.padding(30.dp)) {
Surface(
color = Color.Green,
modifier = Modifier.padding(10.dp).wrapContentSize()) {
Text(text = "My Dummy Text", color = Color.Black)
}
}
}
}

Categories

Resources