在 SwiftUI 中使用获取视图的宽度
Get width of a view using in SwiftUI
我需要在 SwiftUI
中获取渲染视图的宽度,这显然不是那么容易。
我的看法是,我需要一个 returns 视图维度的函数,就这么简单。
var body: some View {
VStack(alignment: .leading) {
Text(timer.name)
.font(.largeTitle)
.fontWeight(.heavy)
Text(timer.time)
.font(.largeTitle)
.fontWeight(.heavy)
.opacity(0.5)
}
}
获得 View
尺寸的唯一方法是使用 GeometryReader
。 reader returns 容器的尺寸。
什么是几何reader?文档说:
A container view that defines its content as a function of its own size and coordinate space. Apple Doc
所以你可以通过这样做得到尺寸:
struct ContentView: View {
@State var frame: CGSize = .zero
var body: some View {
HStack {
GeometryReader { (geometry) in
self.makeView(geometry)
}
}
}
func makeView(_ geometry: GeometryProxy) -> some View {
print(geometry.size.width, geometry.size.height)
DispatchQueue.main.async { self.frame = geometry.size }
return Text("Test")
.frame(width: geometry.size.width)
}
}
打印的尺寸是HStack
内视图容器的尺寸。
您可以使用另一个 GeometryReader
来获取内部尺寸。
但请记住,SwiftUI 是一个声明式框架。所以你应该避免计算视图的尺寸:
阅读更多示例:
获取子视图的尺寸是任务的第一部分。冒泡维度的价值是第二部分。 GeometryReader
获取父视图的 dims,这可能不是您想要的。为了获得相关子视图的亮度,我们可能会在其子视图上调用一个修饰符,该修饰符具有实际大小,例如 .background()
或 .overlay()
struct GeometryGetterMod: ViewModifier {
@Binding var rect: CGRect
func body(content: Content) -> some View {
print(content)
return GeometryReader { (g) -> Color in // (g) -> Content in - is what it could be, but it doesn't work
DispatchQueue.main.async { // to avoid warning
self.rect = g.frame(in: .global)
}
return Color.clear // return content - doesn't work
}
}
}
struct ContentView: View {
@State private var rect1 = CGRect()
var body: some View {
let t = HStack {
// make two texts equal width, for example
// this is not a good way to achieve this, just for demo
Text("Long text").overlay(Color.clear.modifier(GeometryGetterMod(rect: $rect1)))
// You can then use rect in other places of your view:
Text("text").frame(width: rect1.width, height: rect1.height).background(Color.green)
Text("text").background(Color.yellow)
}
print(rect1)
return t
}
}
这是另一种获取和处理当前视图大小的便捷方式:readSize
函数。
extension View {
func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self, perform: onChange)
}
}
private struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
用法:
struct ContentView: View {
@State private var commonSize = CGSize()
var body: some View {
VStack {
Text("Hello, world!")
.padding()
.border(.yellow, width: 1)
.readSize { textSize in
commonSize = textSize
}
Rectangle()
.foregroundColor(.yellow)
.frame(width: commonSize.width, height: commonSize.height)
}
}
}
我需要在 SwiftUI
中获取渲染视图的宽度,这显然不是那么容易。
我的看法是,我需要一个 returns 视图维度的函数,就这么简单。
var body: some View {
VStack(alignment: .leading) {
Text(timer.name)
.font(.largeTitle)
.fontWeight(.heavy)
Text(timer.time)
.font(.largeTitle)
.fontWeight(.heavy)
.opacity(0.5)
}
}
获得 View
尺寸的唯一方法是使用 GeometryReader
。 reader returns 容器的尺寸。
什么是几何reader?文档说:
A container view that defines its content as a function of its own size and coordinate space. Apple Doc
所以你可以通过这样做得到尺寸:
struct ContentView: View {
@State var frame: CGSize = .zero
var body: some View {
HStack {
GeometryReader { (geometry) in
self.makeView(geometry)
}
}
}
func makeView(_ geometry: GeometryProxy) -> some View {
print(geometry.size.width, geometry.size.height)
DispatchQueue.main.async { self.frame = geometry.size }
return Text("Test")
.frame(width: geometry.size.width)
}
}
打印的尺寸是HStack
内视图容器的尺寸。
您可以使用另一个 GeometryReader
来获取内部尺寸。
但请记住,SwiftUI 是一个声明式框架。所以你应该避免计算视图的尺寸:
阅读更多示例:
获取子视图的尺寸是任务的第一部分。冒泡维度的价值是第二部分。 GeometryReader
获取父视图的 dims,这可能不是您想要的。为了获得相关子视图的亮度,我们可能会在其子视图上调用一个修饰符,该修饰符具有实际大小,例如 .background()
或 .overlay()
struct GeometryGetterMod: ViewModifier {
@Binding var rect: CGRect
func body(content: Content) -> some View {
print(content)
return GeometryReader { (g) -> Color in // (g) -> Content in - is what it could be, but it doesn't work
DispatchQueue.main.async { // to avoid warning
self.rect = g.frame(in: .global)
}
return Color.clear // return content - doesn't work
}
}
}
struct ContentView: View {
@State private var rect1 = CGRect()
var body: some View {
let t = HStack {
// make two texts equal width, for example
// this is not a good way to achieve this, just for demo
Text("Long text").overlay(Color.clear.modifier(GeometryGetterMod(rect: $rect1)))
// You can then use rect in other places of your view:
Text("text").frame(width: rect1.width, height: rect1.height).background(Color.green)
Text("text").background(Color.yellow)
}
print(rect1)
return t
}
}
这是另一种获取和处理当前视图大小的便捷方式:readSize
函数。
extension View {
func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self, perform: onChange)
}
}
private struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
用法:
struct ContentView: View {
@State private var commonSize = CGSize()
var body: some View {
VStack {
Text("Hello, world!")
.padding()
.border(.yellow, width: 1)
.readSize { textSize in
commonSize = textSize
}
Rectangle()
.foregroundColor(.yellow)
.frame(width: commonSize.width, height: commonSize.height)
}
}
}