在SwiftUI中使用aspectRatio的方形文本

在SwiftUI中使用aspectRatio的方形文本,swiftui,Swiftui,我正在尝试使用Swift UI实现以下布局 我希望文本(“I”)为方形,但设置.aspectRatio(1,contentMode:.fill)似乎没有任何作用 我可以设置文本的框架宽度和高度,使其为正方形,但似乎设置纵横比应该以更动态的方式实现我想要的效果 我遗漏了什么?我在SwiftUI的第一个屏幕截图中重新创建了视图。我不确定您需要多少填充,因此为此值定义了一个private不可变变量 蓝色视图将包含文本内容,并且大小可能会改变,因此通过使用GeometryReader可以获得蓝色视图

我正在尝试使用Swift UI实现以下布局

我希望
文本(“I”)
为方形,但设置
.aspectRatio(1,contentMode:.fill)
似乎没有任何作用

我可以设置文本的框架宽度和高度,使其为正方形,但似乎设置纵横比应该以更动态的方式实现我想要的效果


我遗漏了什么?

我在SwiftUI的第一个屏幕截图中重新创建了视图。我不确定您需要多少填充,因此为此值定义了一个
private
不可变变量

蓝色视图将包含文本内容,并且大小可能会改变,因此通过使用
GeometryReader
可以获得蓝色视图的大小,然后使用大小中的高度值来设置粉红色视图的宽度和高度。这意味着无论蓝色视图的高度是多少,粉色视图都将保持相等的纵横比

下面的
SizeGeter
视图用于使用
GeometryReader
获取任何视图大小,然后将该值绑定回
ContentView
中的
@State
变量。由于使用了
@State
@Binding
属性包装器,因此每当更新
blueViewSize
时,SwiftUI都会自动刷新视图

SizeGetter
视图可用于任何视图,并使用
.background()
修饰符实现,如下所示

struct SizeGetter:View{
@绑定变量大小:CGSize;
var body:一些观点{
//使用GeometryReader获取视图的大小
GeometryReader{中的几何体
组{()->中的任意视图
//从几何体中获取大小
设size=geometry.frame(in:.global).size;
//如果大小已更改,请更新主线程上的大小
//检查大小是否已更改将停止无限布局循环
如果(大小!=自身大小){
DispatchQueue.main.async{
自我尺寸=尺寸;
}
}
//返回空视图
返回AnyView(EmptyView());
}
}
}
}
结构ContentView:View{
私有let填充:长度=10;
@国家私有变量blueViewSize:CGSize=.0;
var body:一些观点{
列表(1…5){中的索引
//黄色视图
HStack(间距:自填充){
//蓝色风景
HStack(间距:0){
VStack(间距:0){
文本(“项目编号\(索引)”)
.填充(自填充);
}
垫片();
}
.background(SizeGeter(大小:self.$blueViewSize))
.背景(颜色:蓝色);
//粉色风景
VStack(间距:0){
文本(“i”)
.font(.title)
.italic();
}
.框架(
宽度:self.blueViewSize.height,
高度:self.blueViewSize.height
)
.背景(颜色:粉红色);
}
.padding(自填充)
.背景(颜色.黄色);
}
}
}

在我看来,最好设置
VStack
HStack
的背景色,而不是直接设置
Text
视图,因为这样可以向堆栈中添加更多文本和其他视图,而不必为每个视图设置背景色,遇到您的问题,我想我已经找到了实现所需布局的非常简单的方法,使用GeometryProxy从提供的geometry.size设置正方形视图的宽度和高度

签出下面的代码,这是一个可在列表视图上下文中使用的TableCellView示例:

import SwiftUI

struct TableCellView: View {
    var index: Int
    
    var body: some View {
        HStack {
            HStack {
                Text("Item number \(index)")
                    .padding([.top, .leading, .bottom])
                Spacer()
            }
            .background(Color(.systemBlue))
            .layoutPriority(1)
            
            GeometryReader { geometry in
                self.squareView(geometry: geometry)
            }
            .padding(.trailing)
        }
        .background(Color(.systemYellow))
        .padding(.trailing)
    }
    
    func squareView(geometry: GeometryProxy) -> some View {
        Text("i")
            .frame(width: geometry.size.height, height: geometry.size.height)
            .background(Color(.systemPink))
    }
}

问题是由于左右两侧使用了不同的字体,因此填充产生了不同的结果区域

这是可能的解决办法。其思想是根据左侧文本的默认视图大小提供右侧rect(这也提供了自动跟踪动态字体大小的能力)

使用Xcode 12/iOS 14进行测试


我想这就是你想要的:

List(1..<6) { index  in
                HStack {
                    HStack {
                        Text("Item number \(index)")
                        
                        Spacer()
                    }
                    .padding([.leading, .top, .bottom])
                    .background(Color.blue)
                    
                    Text("i")
                        .font(.title)
                        .italic()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .aspectRatio(1, contentMode: .fill)
                        .background(Color.pink)
                        .fixedSize(horizontal: true, vertical: false)
                        .padding(.leading, 6)
                }
                .padding(6)
                .background(Color.yellow)
            }

列表(1..谢谢,但正如我在问题末尾所指出的,我试图避免为粉红色的宽度/高度设置硬编码值square@AshleyMills很抱歉,请看我的最新答案谢谢你花时间写这封信…我不得不相信有一个更简单的方法!@AshleyMills没问题!苹果可能会添加一个在SwiftUI的未来版本中,这样做不太复杂,但目前SwiftUI仍处于测试阶段,我认为10个月后没有其他方法了。你找到一个好方法来制作一个没有GeometryReader的textView square吗?太好了,谢谢。我想感谢你的是
fixedSize
,看起来有几种方法可以去除它这是一只特别的猫。
struct ContentView: View {
    @State private var height = CGFloat.zero
    var body: some View {
        List(1...5, id: \.self) { index  in

            HStack(spacing: 8) {
                HStack {
                    Text("Item number \(index)")
                    Spacer()
                    }
                    .padding([.leading, .top, .bottom])
                    .background(GeometryReader {
                        Color.blue.preference(key: ViewHeightKey.self, value: $0.frame(in: .local).size.height)
                    })


                Text("i")
                    .italic()
                    .font(.title)
                    .frame(width: height, height: height)
                    .background(Color.pink)

                }
                .padding(8)
                .background(Color.yellow)
                .onPreferenceChange(ViewHeightKey.self) {
                    self.height = $0
                }
        }
    }
}

struct ViewHeightKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value += nextValue()
    }
}
List(1..<6) { index  in
                HStack {
                    HStack {
                        Text("Item number \(index)")
                        
                        Spacer()
                    }
                    .padding([.leading, .top, .bottom])
                    .background(Color.blue)
                    
                    Text("i")
                        .font(.title)
                        .italic()
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .aspectRatio(1, contentMode: .fill)
                        .background(Color.pink)
                        .fixedSize(horizontal: true, vertical: false)
                        .padding(.leading, 6)
                }
                .padding(6)
                .background(Color.yellow)
            }