Add border API, update border style
This commit is contained in:
1 parent
4e2c1a10cb
commit
abee093c01
8 files changed
+114
-26
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -49,6 +49,7 @@ import androidx.compose.ui.util.fastCoerceAtMost
|
||||
import com.kyant.expressa.prelude.*
|
||||
import com.kyant.expressa.shape.RoundedRectangle
|
||||
import com.kyant.glass.R
|
||||
import com.kyant.liquidglass.GlassLightBorderBrush
|
||||
import com.kyant.liquidglass.LocalLiquidGlassProviderState
|
||||
import com.kyant.liquidglass.liquidGlassProvider
|
||||
import com.kyant.liquidglass.rememberLiquidGlassProviderState
|
||||
@@ -164,13 +165,21 @@ fun Preview() {
|
||||
.drawWithCache { // border
|
||||
val shape = RoundedRectangle(state.cornerRadius.value)
|
||||
val outline = shape.createOutline(size, layoutDirection, this)
|
||||
val cornerRadiusPx = state.cornerRadius.value.toPx()
|
||||
val borderWidthPx = 3.dp.toPx()
|
||||
val brush =
|
||||
GlassLightBorderBrush(
|
||||
color = Color.White,
|
||||
cornerRadius = cornerRadiusPx,
|
||||
borderWidth = borderWidthPx
|
||||
)
|
||||
|
||||
onDrawWithContent {
|
||||
drawContent()
|
||||
drawOutline(
|
||||
outline = outline,
|
||||
color = Color.White.copy(alpha = 0.2f),
|
||||
style = Stroke(3.dp.toPx()),
|
||||
brush = brush,
|
||||
style = Stroke(borderWidthPx),
|
||||
blendMode = BlendMode.Plus
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.kyant.liquidglass
|
||||
|
||||
import android.graphics.RuntimeShader
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shader
|
||||
import androidx.compose.ui.graphics.ShaderBrush
|
||||
import kotlin.math.PI
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
class GlassLightBorderBrush(
|
||||
private val color: Color,
|
||||
private val cornerRadius: Float,
|
||||
private val borderWidth: Float
|
||||
) : ShaderBrush() {
|
||||
|
||||
override fun createShader(size: Size): Shader {
|
||||
return RuntimeShader(
|
||||
"""// This file belongs to Kyant. You must not use it without permission.
|
||||
${LiquidGlassShaders.sdRectangleShaderUtils}
|
||||
|
||||
half4 main(float2 coord) {
|
||||
float cornerRadius = ${cornerRadius};
|
||||
float2 size = float2(${size.width}, ${size.height});
|
||||
float2 halfSize = size * 0.5;
|
||||
float2 centeredCoord = coord - halfSize;
|
||||
|
||||
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, cornerRadius);
|
||||
float2 topLightNormal = float2(-cos(${75.0 / 180.0 * PI}), -sin(${75.0 / 180.0 * PI}));
|
||||
float topLightFraction = dot(topLightNormal, grad);
|
||||
float bottomLightFraction = dot(-topLightNormal, grad);
|
||||
float fraction = pow(max(topLightFraction, bottomLightFraction), 5.0);
|
||||
|
||||
float sd = sdRoundedRectangle(centeredCoord, halfSize, cornerRadius);
|
||||
sd = min(sd, 0.0);
|
||||
fraction = mix(fraction, 0.0, pow(-sd / $borderWidth, 0.5));
|
||||
|
||||
return half4(${color.red}, ${color.green}, ${color.blue}, ${color.alpha}) * fraction;
|
||||
}"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.BlendMode
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||
import androidx.compose.ui.graphics.drawOutline
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
@@ -21,7 +20,6 @@ import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.layer.drawLayer
|
||||
import androidx.compose.ui.layout.boundsInRoot
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun Modifier.liquidGlass(
|
||||
@@ -135,6 +133,17 @@ fun Modifier.liquidGlass(
|
||||
graphicsLayer.renderEffect = renderEffect
|
||||
|
||||
val outline = style.shape.createOutline(size, layoutDirection, this)
|
||||
val borderWidthPx = style.borderWidth.toPx()
|
||||
val borderBrush =
|
||||
if (borderWidthPx > 0f) {
|
||||
GlassLightBorderBrush(
|
||||
color = style.borderColor,
|
||||
cornerRadius = cornerRadiusPx,
|
||||
borderWidth = borderWidthPx
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
onDrawBehind {
|
||||
val rect = rect ?: return@onDrawBehind
|
||||
@@ -143,15 +152,18 @@ fun Modifier.liquidGlass(
|
||||
drawLayer(providerState.graphicsLayer)
|
||||
}
|
||||
}
|
||||
|
||||
drawLayer(graphicsLayer)
|
||||
borderBrush?.let {
|
||||
drawOutline(
|
||||
outline = outline,
|
||||
color = Color.White.copy(alpha = 0.2f),
|
||||
style = Stroke(3.dp.toPx()),
|
||||
brush = it,
|
||||
style = Stroke(borderWidthPx),
|
||||
blendMode = BlendMode.Plus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onGloballyPositioned { layoutCoordinates ->
|
||||
rect = providerState.rect?.let {
|
||||
layoutCoordinates.boundsInRoot().translate(-it.topLeft)
|
||||
|
||||
@@ -10,15 +10,10 @@ internal object LiquidGlassShaders {
|
||||
|
||||
float luma(half4 color) {
|
||||
return dot(toLinearSrgb(color.rgb), rgbToY);
|
||||
}
|
||||
""".trimIndent()
|
||||
}"""
|
||||
|
||||
@Language("AGSL")
|
||||
private val refractionShaderUtils = """// This file belongs to Kyant. You must not use it without permission.
|
||||
float circleMap(float x) {
|
||||
return 1.0 - sqrt(1.0 - x * x);
|
||||
}
|
||||
|
||||
internal val sdRectangleShaderUtils = """// This file belongs to Kyant. You must not use it without permission.
|
||||
float sdRectangle(float2 coord, float2 halfSize) {
|
||||
float2 d = abs(coord) - halfSize;
|
||||
float outside = length(max(d, 0.0));
|
||||
@@ -40,6 +35,14 @@ internal object LiquidGlassShaders {
|
||||
} else {
|
||||
return sign(coord) * ((-cornerCoord.x < -cornerCoord.y) ? float2(1.0, 0.0) : float2(0.0, 1.0));
|
||||
}
|
||||
}"""
|
||||
|
||||
@Language("AGSL")
|
||||
private val refractionShaderUtils = """// This file belongs to Kyant. You must not use it without permission.
|
||||
$sdRectangleShaderUtils
|
||||
|
||||
float circleMap(float x) {
|
||||
return 1.0 - sqrt(1.0 - x * x);
|
||||
}
|
||||
|
||||
half4 refractionColor(float2 coord, float2 size, float cornerRadius, float eccentricFactor, float height, float amount) {
|
||||
@@ -65,8 +68,7 @@ internal object LiquidGlassShaders {
|
||||
} else {
|
||||
return image.eval(coord);
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}"""
|
||||
|
||||
@Language("AGSL")
|
||||
val refractionShaderString = """// This file belongs to Kyant. You must not use it without permission.
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@@ -13,6 +14,8 @@ import androidx.compose.ui.unit.dp
|
||||
fun LiquidGlassStyle(
|
||||
shape: CornerBasedShape,
|
||||
blurRadius: Dp = 2.dp,
|
||||
borderWidth: Dp = 3.dp,
|
||||
borderColor: Color = Color.White,
|
||||
|
||||
refractionHeight: Dp = 8.dp,
|
||||
refractionAmount: Dp = (-16).dp,
|
||||
@@ -29,6 +32,8 @@ fun LiquidGlassStyle(
|
||||
ImmutableLiquidGlassStyle(
|
||||
shape = shape,
|
||||
blurRadius = blurRadius,
|
||||
borderWidth = borderWidth,
|
||||
borderColor = borderColor,
|
||||
refractionHeight = refractionHeight,
|
||||
refractionAmount = refractionAmount,
|
||||
eccentricFactor = eccentricFactor,
|
||||
@@ -43,6 +48,8 @@ fun LiquidGlassStyle(
|
||||
fun MutableLiquidGlassState(
|
||||
shape: CornerBasedShape,
|
||||
blurRadius: Dp = 2.dp,
|
||||
borderWidth: Dp = 3.dp,
|
||||
borderColor: Color = Color.White,
|
||||
|
||||
refractionHeight: Dp = 8.dp,
|
||||
refractionAmount: Dp = (-16).dp,
|
||||
@@ -58,17 +65,19 @@ fun MutableLiquidGlassState(
|
||||
): MutableLiquidGlassState =
|
||||
MutableLiquidGlassState(
|
||||
initialStyle = ImmutableLiquidGlassStyle(
|
||||
shape,
|
||||
blurRadius,
|
||||
refractionHeight,
|
||||
refractionAmount,
|
||||
eccentricFactor,
|
||||
bleedAmount,
|
||||
bleedBlurRadius,
|
||||
bleedOpacity,
|
||||
contrast,
|
||||
whitePoint,
|
||||
chromaMultiplier
|
||||
shape = shape,
|
||||
blurRadius = blurRadius,
|
||||
borderWidth = borderWidth,
|
||||
borderColor = borderColor,
|
||||
refractionHeight = refractionHeight,
|
||||
refractionAmount = refractionAmount,
|
||||
eccentricFactor = eccentricFactor,
|
||||
bleedAmount = bleedAmount,
|
||||
bleedBlurRadius = bleedBlurRadius,
|
||||
bleedOpacity = bleedOpacity,
|
||||
contrast = contrast,
|
||||
whitePoint = whitePoint,
|
||||
chromaMultiplier = chromaMultiplier
|
||||
)
|
||||
)
|
||||
|
||||
@@ -78,6 +87,10 @@ sealed interface LiquidGlassStyle {
|
||||
|
||||
val blurRadius: Dp
|
||||
|
||||
val borderWidth: Dp
|
||||
|
||||
val borderColor: Color
|
||||
|
||||
val refractionHeight: Dp
|
||||
|
||||
val refractionAmount: Dp
|
||||
@@ -106,6 +119,8 @@ class ImmutableLiquidGlassStyle
|
||||
internal constructor(
|
||||
override val shape: CornerBasedShape,
|
||||
override val blurRadius: Dp = 2.dp,
|
||||
override val borderWidth: Dp = 3.dp,
|
||||
override val borderColor: Color = Color.White,
|
||||
|
||||
override val refractionHeight: Dp = 8.dp,
|
||||
override val refractionAmount: Dp = (-16).dp,
|
||||
@@ -123,6 +138,8 @@ internal constructor(
|
||||
fun copy(
|
||||
shape: CornerBasedShape = this.shape,
|
||||
blurRadius: Dp = this.blurRadius,
|
||||
borderWidth: Dp = this.borderWidth,
|
||||
borderColor: Color = this.borderColor,
|
||||
|
||||
refractionHeight: Dp = this.refractionHeight,
|
||||
refractionAmount: Dp = this.refractionAmount,
|
||||
@@ -139,6 +156,8 @@ internal constructor(
|
||||
ImmutableLiquidGlassStyle(
|
||||
shape = shape,
|
||||
blurRadius = blurRadius,
|
||||
borderWidth = borderWidth,
|
||||
borderColor = borderColor,
|
||||
refractionHeight = refractionHeight,
|
||||
refractionAmount = refractionAmount,
|
||||
eccentricFactor = eccentricFactor,
|
||||
@@ -158,6 +177,8 @@ internal constructor(
|
||||
|
||||
override var shape: CornerBasedShape by mutableStateOf(initialStyle.shape)
|
||||
override var blurRadius: Dp by mutableStateOf(initialStyle.blurRadius)
|
||||
override var borderWidth: Dp by mutableStateOf(initialStyle.borderWidth)
|
||||
override var borderColor: Color by mutableStateOf(initialStyle.borderColor)
|
||||
|
||||
override var refractionHeight: Dp by mutableStateOf(initialStyle.refractionHeight)
|
||||
override var refractionAmount: Dp by mutableStateOf(initialStyle.refractionAmount)
|
||||
|
||||
Reference in new issue
Block a user