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