我创建了一个自定义形状的形式环段。我最终想在我的应用程序中使用这个形状作为按钮,因此我需要能够将文本定位在它的正中间。下面的图片显示了环段(蓝色)和文本(红色),我希望在蓝色段内垂直居中。
下面的代码创建自定义蓝色形状段:
struct CurvedButtonData {
enum ButtonLocation {
case top
case right
case bottom
case left
}
/// The button's width as an angle in degrees.
let width: Double = 90.0
/// The button's start location, as an angle in degrees.
fileprivate(set) var start = 0.0
/// The button's end location, as an angle in degrees.
fileprivate(set) var end = 0.0
init(position: ButtonLocation) {
switch position {
case .top:
start = -135
case .right:
start = -45
case .bottom:
start = 45
case .left:
start = 135
}
end = start + width
}
}
struct CurvedButton: Shape, InsettableShape {
let data: CurvedButtonData
var insetAmount = 0.0
func path(in rect: CGRect) -> Path {
let points = CurvedButtonGeometry(curvedButtonData: data, rect: rect)
var path = Path()
path.addArc(center: points.center, radius: points.innerRadius, startAngle: .degrees(data.start), endAngle: .degrees(data.end), clockwise: false)
path.addArc(center: points.center, radius: points.outerRadius - insetAmount, startAngle: .degrees(data.end), endAngle: .degrees(data.start), clockwise: true)
path.closeSubpath()
return path
}
func inset(by amount: CGFloat) -> CurvedButton {
var button = self
button.insetAmount += amount
return button
}
}
struct CurvedButtonGeometry {
let data: CurvedButtonData
let center: CGPoint
let innerRadius: CGFloat
let outerRadius: CGFloat
init(curvedButtonData: CurvedButtonData, rect: CGRect) {
center = CGPoint(x: rect.midX, y: rect.midY)
let radius = min(rect.width, rect.height) / 4
innerRadius = radius
outerRadius = radius * 2
data = curvedButtonData
}
/// Returns the view location of the point in the wedge at unit-
/// space location `unitPoint`, where the X axis of `p` moves around the
/// wedge arc and the Y axis moves out from the inner to outer
/// radius.
subscript(unitPoint: UnitPoint) -> CGPoint {
let radius = lerp(innerRadius, outerRadius, by: unitPoint.y)
let angle = lerp(data.start, data.end, by: Double(unitPoint.x))
return CGPoint(x: center.x + CGFloat(cos(angle)) * radius,
y: center.y + CGFloat(sin(angle)) * radius)
}
/// Linearly interpolate from `from` to `to` by the fraction `amount`.
private func lerp<T: BinaryFloatingPoint>(_ fromValue: T, _ toValue: T, by amount: T) -> T {
return fromValue + (toValue - fromValue) * amount
}
}
这是我可怜的尝试,用我的自定义形状创建一个按钮,并将“Click me”文本置于蓝色区域的中心:
import SwiftUI
struct CircularCVBControl: View {
var body: some View {
Button {
} label: {
ZStack(alignment: .top) {
CurvedButton(data: .init(position: .top))
.fill(.blue)
.overlay(alignment: .top) {
Text("Click me")
.foregroundColor(.red)
}
}
}
.buttonStyle(.plain)
}
}
struct CircularCVBControl_Previews: PreviewProvider {
static var previews: some View {
CircularCVBControl()
}
}
我现在怎么能整齐(和 * 没有使用一个hacky填充 * 的文本)中心的文本垂直在我的自定义形状?我正在寻找一些自定义对齐指南/逻辑排序的工作。此外,形状也可以在其他方向上旋转,文本也应该随之旋转。
2条答案
按热度按时间erhoui1w1#
问题是你的曲线没有在帧的中间渲染。为了解决这个问题,我认为你需要抵消你的中心。就像这样:
这是一个仅适用于“.top”位置的解决方案。其他的职位就交给你了;- )
下面是完整的代码:
2hh7jdfx2#
我看到你想把多个Curvedbuttons组合在一起作为一个“圆”。在这种情况下,您确实需要偏移文本而不是形状。你可以使用GeometryReader。我已经为.top位置实现了它,如下所示。您可以将其他位置添加到getOffset()方法中。我对这段代码并不完全满意,因为有些坐标不是在一个以上的地方计算的。你可以/应该清理这个代码很多,但我想展示的核心原则,而不改变一切。希望这能帮上忙。