在自定义形状上垂直居中文本 - SwiftUI

问题描述 投票:0回答:0

我创建了一个环形段形式的自定义形状。我最终想在我的应用程序中使用这个形状作为按钮,因此我需要能够将文本放在它的中间。下图显示了环段(蓝色)和我希望在蓝色段内垂直居中的文本(红色)。

下面的代码创建自定义蓝色形状段:

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
    }
}

这是我用我的自定义形状创建一个按钮并将“单击我”文本居中在蓝色区域内的可惜尝试:

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 padding)将文本垂直居中在我的自定义形状中?我正在寻找某种可以完成这项工作的自定义对齐指南/逻辑。此外,形状也可以向其他方向旋转,文本也应随之旋转。

swift xcode swiftui shapes
© www.soinside.com 2019 - 2024. All rights reserved.