如何使用角度参数自定义Brush.linearGradient(),例如0、45、90、135等任意角度?
谢谢。
如何使用角度参数自定义Brush.linearGradient(),例如0、45、90、135等任意角度?
谢谢。
任意角度的线性渐变看起来很不错,但需要做太多工作...
而设置角度为0、45、90、135...相对较简单。使用Brush.linearGradient(...)方法,您可以组合参数start
和end
来实现。
首先看看这个函数:
@Stable
fun linearGradient(
colors: List<Color>,
start: Offset = Offset.Zero,
end: Offset = Offset.Infinite,
tileMode: TileMode = TileMode.Clamp
)
从默认参数值(start,end)我们可以得出缺省角度为 135。那是因为什么呢?
start = Offset.Zero == Offset(0f, Float.POSITIVE_INFINITY)
end = Offset.Infinite == Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
从笛卡尔坐标系的起点到终点,可以看出方向是右下,因此角度为135度。因此,我们可以得出结论。
angle 0
start = Offset(0f,0f)
end = Offset(Float.INFINITY,0f)
angle 45
start = Offset(0f, Float.POSITIVE_INFINITY)
end = Offset(Float.POSITIVE_INFINITY, 0f)
angle 90
start = Offset(0f, Float.POSITIVE_INFINITY)
end = Offset(0f,0f)
...
``
实现顺时针45度间隔的配额
fun GradientOffset(angle: GradientAngle): GradientOffset {
return when (angle) {
GradientAngle.CW45 -> GradientOffset(
start = Offset.Zero,
end = Offset.Infinite
)
GradientAngle.CW90 -> GradientOffset(
start = Offset.Zero,
end = Offset(0f, Float.POSITIVE_INFINITY)
)
GradientAngle.CW135 -> GradientOffset(
start = Offset(Float.POSITIVE_INFINITY, 0f),
end = Offset(0f, Float.POSITIVE_INFINITY)
)
GradientAngle.CW180 -> GradientOffset(
start = Offset(Float.POSITIVE_INFINITY, 0f),
end = Offset.Zero,
)
GradientAngle.CW225 -> GradientOffset(
start = Offset.Infinite,
end = Offset.Zero
)
GradientAngle.CW270 -> GradientOffset(
start = Offset(0f, Float.POSITIVE_INFINITY),
end = Offset.Zero
)
GradientAngle.CW315 -> GradientOffset(
start = Offset(0f, Float.POSITIVE_INFINITY),
end = Offset(Float.POSITIVE_INFINITY, 0f)
)
else -> GradientOffset(
start = Offset.Zero,
end = Offset(Float.POSITIVE_INFINITY, 0f)
)
}
}
/**
* Offset for [Brush.linearGradient] to rotate gradient depending on [start] and [end] offsets.
*/
data class GradientOffset(val start: Offset, val end: Offset)
enum class GradientAngle {
CW0, CW45, CW90, CW135, CW180, CW225, CW270, CW315
}
使用方法
// Offsets for gradients based on selected angle
var gradientOffset by remember {
mutableStateOf(GradientOffset(GradientAngle.CW0))
}
val redGreenGradient = Brush.linearGradient(
colors = listOf(Color.Red, Color.Green, Color.Blue),
start = gradientOffset.start,
end = gradientOffset.end
)
完整演示
使用枚举类定义顺时针旋转,获取 Brush.linearGradient
的 GradientOffset
,返回起始和结束的偏移量
@Composable
fun GradientRotationDemo() {
val canvasSize = 300.dp
val canvasModifier = Modifier
.size(canvasSize)
// Offsets for gradients based on selected angle
var gradientOffset by remember {
mutableStateOf(GradientOffset(GradientAngle.CW0))
}
var angleSelection by remember { mutableStateOf(0f) }
var angleText by remember { mutableStateOf("0 Degrees") }
Column(
modifier = Modifier
.fillMaxSize()
.background(backgroundColor)
.padding(8.dp)
) {
Text(
text = angleText,
color = Blue400,
modifier = Modifier
.padding(8.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Slider(
modifier = Modifier.height(50.dp),
value = angleSelection,
onValueChange = {
angleSelection = it
gradientOffset = when (angleSelection.roundToInt()) {
0 -> {
angleText = "0 Degrees"
GradientOffset(GradientAngle.CW0)
}
1 -> {
angleText = "45 Degrees"
GradientOffset(GradientAngle.CW45)
}
2 -> {
angleText = "90 Degrees"
GradientOffset(GradientAngle.CW90)
}
3 -> {
angleText = "135 Degrees"
GradientOffset(GradientAngle.CW135)
}
4 -> {
angleText = "180 Degrees"
GradientOffset(GradientAngle.CW180)
}
5 -> {
angleText = "225 Degrees"
GradientOffset(GradientAngle.CW225)
}
6 -> {
angleText = "270 Degrees"
GradientOffset(GradientAngle.CW270)
}
else -> {
angleText = "315 Degrees"
GradientOffset(GradientAngle.CW315)
}
}
},
steps = 6,
valueRange = 0f..7f
)
Column(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
CanvasWithTitle(
modifier = canvasModifier,
text = "Gradient"
) {
val redGreenGradient = Brush.linearGradient(
colors = listOf(Color.Red, Color.Green, Color.Blue),
)
drawRect(redGreenGradient)
}
CanvasWithTitle(
modifier = canvasModifier,
text = "Gradient Angle"
) {
val redGreenGradient = Brush.linearGradient(
colors = listOf(Color.Red, Color.Green, Color.Blue),
start = gradientOffset.start,
end = gradientOffset.end
)
drawRect(redGreenGradient)
}
}
}
}
CanvasWithTitle 没有什么特别的,但为了方便测试,我也将其添加进去了。
private fun CanvasWithTitle(
modifier: Modifier = Modifier,
text: String,
onDraw: DrawScope.() -> Unit
) {
Column(
modifier = Modifier
.wrapContentWidth()
) {
Text(
text = text,
color = Blue400,
modifier = Modifier
.padding(8.dp),
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Canvas(modifier = modifier, onDraw = onDraw)
}
}
顺便提一下,刷子线性渐变的初始旋转角度为逆时针315度,或顺时针45度。
结果,上面的是默认的渐变,下面的是通过获取开始和结束偏移量应用旋转函数后的渐变。
要旋转任意角度,需要创建一个函数来获取您的Composable的宽度和高度,并进行二维旋转。
xNew = x*cos(angle) - y*sin(angle)
yNew = x*sin(angle) + y*cos(angle)
但不确定如何将其翻译回轴,以使旋转45度的函数具有相同的值。