Closed WebTiger89 closed 1 year ago
The issue is that any modifier we add to the ExtendedFloatingActionButton
will be applied before the actual shadow and clipping is applied.
This will cause the shimmer
-Modifier to draw the effect on the shadow and therefore background as well.
If you don't care about the shadow too much, you can simply clip the shimmering. The shape
I'm using here is the default parameter of the FAB.
ExtendedFloatingActionButton(
modifier = Modifier
.clip(MaterialTheme.shapes.small.copy(CornerSize(percent = 50)))
.shimmer(),
...
If you want to keep the shadow, you have to apply it yourself:
val interactionSource = remember { MutableInteractionSource() }
val elevation = FloatingActionButtonDefaults.elevation()
ExtendedFloatingActionButton(
modifier = Modifier
.shadow(
elevation = elevation.elevation(interactionSource = interactionSource).value,
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
clip = true,
)
.shimmer(),
interactionSource = interactionSource,
...
If you are using a shimmer that has an alpha value, the later might look a bit weird when pushing the button. That's because two shadows are now drawn within the clipping area, underneath the button.
But I think you could play around a little bit and see what fits best for your app. Try using a fixed elevation for example.
Thanks for the fast reply. Works so far. Unfortunately this part does not work elevation.elevation(interactionSource = interactionSource).value
I have checked the source code of FAB and the FloatingActionButtonElevation
instance does not has any public functions. I would need elevation.shadowElevation(interactionSource = interactionSource).value
but this fun is internal. Does material 3 lack support for this case here or did I miss something?
If the matter is shadow(elevation effect) then look https://github.com/Debdutta-Panda/CustomShadow/blob/master/app/src/main/java/com/debduttapanda/customshadow/MainActivity.kt#L248
I need the delta value of elevation in the different FAB states
Did you get it working in the meantime? If not, let me suggest a different approach. I tried it with material 3 today and it really is difficult.
But we can simply draw a shimmering overlay on top of the FAB:
var isLoading by remember { mutableStateOf(true) }
LaunchedEffect(key1 = true) {
delay(5_000)
isLoading = false
}
Box(
modifier = Modifier
.height(IntrinsicSize.Min)
.width(IntrinsicSize.Min)
) {
ExtendedFloatingActionButton(
onClick = { /* do something */ },
icon = { Icon(Icons.Filled.Add, "Description") },
text = { Text(text = "Extended FAB") },
)
AnimatedVisibility(
visible = isLoading,
exit = fadeOut(animationSpec = tween(500)),
) {
Box(
modifier = Modifier
.fillMaxSize()
.clip(FloatingActionButtonDefaults.extendedFabShape)
.background(Color.LightGray)
.shimmer()
.background(Color.DarkGray)
)
}
}
https://user-images.githubusercontent.com/1201850/218720013-5cf32c1c-8358-402e-899d-4ac62c766164.mov
EDIT: Improved the implementation
Sorry, a little bit late. Thanks for your investigation. I came up with this solution:
@Composable
private fun ScannerFab(
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.extendedFabShape,
isScanning: Boolean,
onAction: () -> Unit = {},
) {
val shimmer = rememberShimmer(
shimmerBounds = ShimmerBounds.View,
theme = defaultShimmerTheme.copy(
blendMode = BlendMode.Hardlight,
rotation = 25f,
shaderColors = listOf(
Color.White.copy(alpha = 0.0f),
Color.White.copy(alpha = 0.6f),
Color.White.copy(alpha = 0.0f),
),
shaderColorStops = null,
shimmerWidth = 400.dp,
),
)
val interactionSource = remember { MutableInteractionSource() }
var shadowElevation by remember { mutableStateOf(6.dp) }
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
shadowElevation = when (interaction) {
is PressInteraction.Press -> 6.dp
is HoverInteraction.Enter -> 8.dp
is FocusInteraction.Focus -> 6.dp
else -> 6.dp
}
}
}
/*
* Since the elevation shadow is rendered before the shimmer effect,
* shimmer effect is applied on the shadow. So disable default elevation shadow and
* render shadow manually, then apply shimmer effect afterwards. By leveraging the
* interaction source, we can control the elevation in different states.
*/
ExtendedFloatingActionButton(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.shadow(
elevation = shadowElevation,
shape = shape,
clip = true,
)
.then(if (isScanning) Modifier.shimmer(shimmer) else Modifier),
onClick = onAction,
shape = shape,
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
interactionSource = interactionSource,
) {
val stringRes = if (isScanning) R.string.btn_searching else R.string.btn_search
Text(stringResource(stringRes).uppercase())
}
}
When applying shimmer modifier on extended FAB which has rounded corners, the shimmer effect is not clipped accordingly.
Any ideas how I can overcome this issue?