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

如何在swiftui中将一个视图绑定到另一个视图?,swiftui,Swiftui,我有一个应用程序,我正在创建一个带有一系列楔子的圆,每个楔子都有一个类别标题,应该出现在楔子的顶部。我创建了楔子和一些弯曲的文本,这些文本应该位于圆的外边缘。然而,当我改变手机的大小时,文字会以不同的比例移动。 所以我的问题是,我如何将文本锚定到圆圈上,这样无论手机大小,它都会保持不变 import SwiftUI struct WedgeShape: Shape { let startAngle: Angle let endAngle: Angle let lineW

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

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

导入快捷界面
结构楔形形状:形状{
让星际缠结:角度
让endAngle:角度
让线宽:CGFloat
func路径(在rect:CGRect中)->path{
var p=Path()
设中心=CGPoint(x:rect.size.width/2,y:rect.size.width/2)
设r1=rect.size.width/2
p、 addArc(中心:中心,半径:绝对值(线宽-r1),星形缠结:星形缠结,端角:端角,顺时针:假)
p、 addArc(中心:中心,半径:r1,星形缠结:端角,端角:星形缠结,顺时针:真)
p、 closeSubpath()
返回p
}
}
结构楔{
var startAngle:双
var端角:双
颜色:颜色
变量文本:字符串
变量偏移量:CGSize
变量旋转:双
变量半径:CGFloat
}
结构楔块:视图{
@环境对象var assesmentClass:评估
让楔子=[
楔块(星形:-90,端角:-45,颜色:颜色。黄色,文本:“评估”,偏移量:CGSize(宽度:-0.0,高度:-15.0),旋转:25,半径:135),
楔块(星形:45,端角:0,颜色:彩色。红色,文本:“划出”,偏移量:CGSize(宽度:0.0,高度:-20.0),旋转:70,半径:130),
楔形(星形:0,端角:45,颜色:color.green,文本:“位置”,偏移量:CGSize(宽度:0.0,高度:-10.0),旋转:110,半径:135),
楔形(星形:45,端角:90,颜色:color.blue,文本:“Catch”,偏移量:CGSize(宽度:0.0,高度:-10.0),旋转:155,半径:135),
楔形(星形:90,端角:135,颜色:color.gray,文本:“起飞”,偏移量:CGSize(宽度:0.0,高度:-10.0),旋转:205,半径:135),
楔形(星形:135,端角:180,颜色:color.yellow,文本:“弹出”,偏移量:CGSize(宽度:5.0,高度:-10.0),旋转:245,半径:135),
楔形(星形:180,端角:225,颜色:color.green,文本:“速度”,偏移量:CGSize(宽度:5.0,高度:-10.0),旋转:290,半径:135),
楔块(星形:225,端角:-90,颜色:color.gray,文本:“操纵”,偏移量:CGSize(宽度:5.0,高度:-35.0),旋转:-25,半径:135)
]
var body:一些观点{
ZStack{
ForEach(0..<楔块计数){
楔形风帽(
星形缠结:角度(度:self.wedges[$0]。星形缠结),
endAngle:Angle(度:self.wedges[$0].endAngle),
线宽:44
)
.foregroundColor(self.wedges[$0].color)
//PieSlice(pies:assesmentClass.makePies())
CurvedText(文本:self.wedges[$0]。文本,半径:self.wedges[$0]。半径,间距:2)。紧排(1)。偏移(self.wedges[$0]。偏移)。前底色(.black)。旋转效果(角度(度:self.wedges[$0]。旋转))
}.scaledofit()
}
}
}
这是视图的代码,正如您所看到的,我使用了带有硬编码值的偏移量,我相信这就是问题所在,但我不确定如何获取动态值,以便动态更改

下面是曲线文本视图的代码

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

//
//斯威夫特曲线
//ombe_冲浪
//
//由Joby Ingram Dodd于2021年4月9日创建。
//
导入快捷键
私有结构TextViewSizeKey:PreferenceKey{
静态变量defaultValue:[CGSize]{[]}
静态函数缩减(值:inout[CGSize],nextValue:()->[CGSize]){
append(contentsOf:nextValue())
}
}
私有结构大小:视图{
var内容:()->V
var body:一些观点{
内容()
.background(GeometryReader{proxy in
Color.clear.preference(键:TextViewSizeKey.self,值:[proxy.size])
})
}
}
私有结构可识别字符:可识别{
变量id:字符串{“\(索引)\(字符)”}
let索引:Int
让角色:角色
}
扩展可识别字符{
变量字符串:字符串{“\(字符)”}
}
扩展阵列{
下标(安全索引:Int)->元素{
索引。包含(索引)?自[索引]:无
}
}
//标记:-曲线文本
公共结构曲线文本:视图{
公共变量文本:字符串
公共变量半径:CGFloat
内部变量textModifier:(Text)->Text={$0}
内部变量间距:CGFloat=0
@国家私有变量大小:[CGSize]=[]
私有函数textRadius(在索引处:Int)->CGFloat{
半径-大小(在:索引处)。高度/2
}
公共机构:一些看法{
VStack{
ZStack{
ForEach(textAsCharacters()){item in
传播大小{
self.textView(字符:项)
}
.frame(宽度:self.size(at:item.index)。宽度,
高度:self.size(at:item.index.height)
.偏移量(x:0,
y:-self.textRadius(at:item.index))
.旋转效应(自身角度(at:项目索引))
}
}
.框架(宽度:半径*2,高度:半径*2)
.onPreferenceChange(TextViewSizeKey.self){中的大小
self.size=大小
}
}
.可访问性(标签:文本)
}
private func textAsCharacters()->[可识别字符]{
let string=string(text.reversed())
返回字符串.enumerated().map(IdentifiableCharacter.init)
}
私有func文本视图(字符:可识别字符)->某些视图{
textModifier(文本(char.string))