如何将视图绑定到 swiftui 中的另一个视图?

时间:2021-04-13 07:02:06

标签: swiftui

我有一个应用程序,我正在用一系列楔子创建一个圆,每个楔子都有一个类别标题,应该出现在楔子的顶部。我创建了楔形和一些弯曲的文本,这些文本应该位于圆圈的外边缘。然而,当我改变手机的大小时,文本会随着不同的比例移动。 所以我的问题是如何将文本锚定到圆圈上,以便无论手机大小如何都保持原位?

import SwiftUI

struct WedgeShape: Shape {
    let startAngle: Angle
    let endAngle: Angle
    let lineWidth: CGFloat

    func path(in rect: CGRect) -> Path {
        var p = Path()
        let center =  CGPoint(x: rect.size.width/2, y: rect.size.width/2)
        let r1 = rect.size.width/2
        p.addArc(center: center, radius: abs(lineWidth - r1), startAngle: startAngle, endAngle: endAngle, clockwise: false)
        p.addArc(center: center, radius: r1, startAngle: endAngle, endAngle: startAngle, clockwise: true)
        p.closeSubpath()
        return p
    }
}

struct Wedge {
    var startAngle: Double
    var endAngle: Double
    var color: Color
    var text: String
    var offset: CGSize
    var rotaion: Double
    var radius: CGFloat
}

struct wedge: View {
    @EnvironmentObject var assesmentClass: Assesments
    
    let wedges = [
        Wedge(startAngle: -90, endAngle: -45, color: Color.yellow, text: "Assess", offset: CGSize(width: -0.0, height: -15.0), rotaion: 25, radius: 135),
        Wedge(startAngle: -45, endAngle: 0, color: Color.red, text: "Paddle Out",offset: CGSize(width: 0.0, height: -20.0), rotaion: 70, radius: 130),
        Wedge(startAngle: 0, endAngle: 45, color: Color.green, text: "Position",offset: CGSize(width: 0.0, height: -10.0), rotaion: 110, radius: 135),
        Wedge(startAngle: 45, endAngle: 90, color: Color.blue, text: "Catch",offset: CGSize(width: 0.0, height: -10.0), rotaion: 155, radius: 135),
        Wedge(startAngle: 90, endAngle: 135, color: Color.gray, text: "Take Off",offset: CGSize(width: 0.0, height: -10.0), rotaion: 205, radius: 135),
        Wedge(startAngle: 135, endAngle: 180, color: Color.yellow, text: "Pop Up",offset: CGSize(width: 5.0, height: -10.0), rotaion: 245, radius: 135),
        Wedge(startAngle: 180, endAngle: 225, color: Color.green, text: "Speed",offset: CGSize(width: 5.0, height: -10.0), rotaion: 290, radius: 135),
        Wedge(startAngle: 225, endAngle: -90, color: Color.gray, text: "Manouvers",offset: CGSize(width: 5.0, height: -35.0), rotaion: -25, radius: 135)
    ]
    
    var body: some View {
        ZStack {
            
            ForEach(0 ..< wedges.count) {
                WedgeShape(
                    startAngle: Angle(degrees: self.wedges[$0].startAngle),
                    endAngle: Angle(degrees: self.wedges[$0].endAngle),
                    lineWidth: 44
                )
                .foregroundColor(self.wedges[$0].color)
                
                //PieSlice(pies: assesmentClass.makePies())
                CurvedText(text: self.wedges[$0].text, radius: self.wedges[$0].radius, spacing: 2).kerning(1).offset(self.wedges[$0].offset).foregroundColor(.black).rotationEffect(Angle(degrees: self.wedges[$0].rotaion))
                
                
            }.scaledToFit()
        }
    }
}

这是视图的代码,正如您所看到的,我使用了硬编码值的偏移量,我相信这是问题所在,但我不确定如何获取动态值以便动态更改。

>

以下是弯曲文本视图的代码。

//
//  CurvedText.swift
//  ombe_surf
//
//  Created by Joby Ingram-Dodd on 09/04/2021.
//
import SwiftUI

private struct TextViewSizeKey: PreferenceKey {
    static var defaultValue: [CGSize] { [] }
    static func reduce(value: inout [CGSize], nextValue: () -> [CGSize]) {
        value.append(contentsOf: nextValue())
    }
}

private struct PropagateSize<V: View>: View {
    var content: () -> V
    var body: some View {
        content()
            .background(GeometryReader { proxy in
                Color.clear.preference(key: TextViewSizeKey.self, value: [proxy.size])
            })
    }
}

private struct IdentifiableCharacter: Identifiable {
    var id: String { "\(index) \(character)" }

    let index: Int
    let character: Character
}

extension IdentifiableCharacter {
    var string: String { "\(character)" }
}

extension Array {
    subscript(safe index: Int) -> Element? {
        indices.contains(index) ? self[index] : nil
    }
}

// MARK: - Curved Text

public struct CurvedText: View {

    public var text: String
    public var radius: CGFloat

    internal var textModifier: (Text) -> Text = { $0 }
    internal var spacing: CGFloat = 0

    @State private var sizes: [CGSize] = []

    private func textRadius(at index: Int) -> CGFloat {
        radius - size(at: index).height / 2
    }

    public var body: some View {
        VStack {
            ZStack {
                ForEach(textAsCharacters()) { item in
                    PropagateSize {
                        self.textView(char: item)
                    }
                    .frame(width: self.size(at: item.index).width,
                           height: self.size(at: item.index).height)
                    .offset(x: 0,
                            y: -self.textRadius(at: item.index))
                    .rotationEffect(self.angle(at: item.index))
                }
            }
            .frame(width: radius * 2, height: radius * 2)
            .onPreferenceChange(TextViewSizeKey.self) { sizes in
                self.sizes = sizes
            }
        }
        .accessibility(label: Text(text))
    }

    private func textAsCharacters() -> [IdentifiableCharacter] {
        let string = String(text.reversed())
        return string.enumerated().map(IdentifiableCharacter.init)
    }

    private func textView(char: IdentifiableCharacter) -> some View {
        textModifier(Text(char.string))
            .rotationEffect(.degrees(180))
    }

    private func size(at index: Int) -> CGSize {
        sizes[safe: index] ?? CGSize(width: 1000000, height: 0)
    }

    private func angle(at index: Int) -> Angle {
        let arcSpacing = Double(spacing / radius)
        let letterWidths = sizes.map { $0.width }

        let prevWidth =
            index < letterWidths.count ?
            letterWidths.dropLast(letterWidths.count - index).reduce(0, +) :
            0
        let prevArcWidth = Double(prevWidth / radius)
        let totalArcWidth = Double(letterWidths.reduce(0, +) / radius)
        let prevArcSpacingWidth = arcSpacing * Double(index)
        let arcSpacingOffset = -arcSpacing * Double(letterWidths.count - 1) / 2
        let charWidth = letterWidths[safe: index] ?? 0
        let charOffset = Double(charWidth / 2 / radius)
        let arcCharCenteringOffset = -totalArcWidth / 2
        let charArcOffset = prevArcWidth + charOffset + arcCharCenteringOffset + arcSpacingOffset + prevArcSpacingWidth
        return Angle(radians: charArcOffset)
    }
}

extension CurvedText {
    public func kerning(_ kerning: CGFloat) -> CurvedText {
        var copy = self
        copy.spacing = kerning
        return copy
    }

    public func italic() -> CurvedText {
        var copy = self
        copy.textModifier = {
            self.textModifier($0)
                .italic()
        }
        return copy
    }

    public func bold() -> CurvedText {
        fontWeight(.bold)
    }

    public func fontWeight(_ weight: Font.Weight?) -> CurvedText {
        var copy = self
        copy.textModifier = {
            self.textModifier($0)
                .fontWeight(weight)
        }
        return copy
    }
}


struct CurvedText_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            CurvedText(text: "Hello World!", radius: 200)

            CurvedText(text: "Hello World!", radius: 100)
                .kerning(5)
                .italic()
                .fontWeight(.heavy)
        }
        .previewLayout(.sizeThatFits)
    }
}

这是屏幕截图。

screen shot

0 个答案:

没有答案