SwiftUI:如何找到图像的高度并使用它来设置框架的大小
SwiftUI: How to find the height of an image and use it to set the size of a frame
所以我一直在尝试弄清楚如何在 SwiftUI 中找到图像的高度,但没有成功。基本上我有 portrait/landscape 图像,我想以大约 600 pt 高显示纵向图像,而我想显示横向图像,因此使用图像的宽度,所以高度是任意的。话虽如此,我希望它在 GeometryReader 内部,因为我使用的偏移量使用它,这样当您向下滚动时,图像不会滚动,但如果您向上滚动,它会滚动。我不相信我可以分享图片,但无论如何,这应该是足以 运行 成功的代码!
struct ContentView: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var backButton: some View {
Button(action: {
withAnimation {
self.mode.wrappedValue.dismiss()
}
}) {
Image(systemName: "chevron.left.circle.fill")
.opacity(0.8)
.font(.system(size: 30))
.foregroundColor(.black)
.background(Color.gray.mask(Image(systemName: "chevron.left").offset(x: 9.4, y: 7.6)))
}
}
var body: some View {
ScrollView(showsIndicators: false) {
GeometryReader { geometry in
Image("image1")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: UIScreen.main.bounds.width, minHeight: 350, maxHeight: 600, alignment: .top)
.clipped()
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
}
.frame(minWidth: UIScreen.main.bounds.width, maxWidth: UIScreen.main.bounds.width, minHeight: 350, idealHeight: 600, maxHeight: 600)
//Message
VStack(alignment: .leading) {
Text("\(07/22/20) - Day \(1)")
.font(.body)
.fontWeight(.light)
.foregroundColor(Color.gray)
.padding(.leading)
Text("what I Love)
.font(.title)
.fontWeight(.bold)
.padding([.leading, .bottom])
Text("paragraph")
.padding([.leading, .bottom, .trailing])
}
}
.edgesIgnoringSafeArea(.all)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton)
}
}
如有任何帮助,我们将不胜感激!
编辑: 这里有两张图片供参考 - 抱歉,我没有意识到你能做到,虽然我早该想到!
如果我没理解错的话,您想要图像的大小以便可以在它自己的框架中使用它的尺寸?您可以创建一个函数,该函数接受图像名称和 returns 您想要的图像,同时还为可以在框架中使用的 width
和 height
设置 @State
变量。
@State var width: CGFloat = 0
@State var height: CGFloat = 0
func image(_ name: String) -> UIImage {
let image = UIImage(named: name)!
let width = image.size.width
let height = image.size.height
DispatchQueue.main.async {
if width > height {
// Landscape image
// Use screen width if < than image width
self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
// Scale height
self.height = self.width/width * height
} else {
// Portrait
// Use 600 if image height > 600
self.height = height > 600 ? 600 : height
// Scale width
self.width = self.height/height * width
}
}
return image
}
用法:
GeometryReader { geometry in
Image(uiImage: image("image1"))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
编辑:添加了 DispatchQueue.main.async
块作为 'Modifying state during view update' 警告的快速修复。可行,但可能不是解决它的绝对最佳方法。将图像放入它自己的 @State
并在视图的 onAppear
方法中设置它可能更好。
编辑 2:将图像移动到它自己的 @State
var 中,我认为这是一个更好的解决方案,因为它会使视图更易于重用,因为您可以传递图像而不是硬编码图像的名称在视图中。
@State var image: UIImage {
didSet {
let width = image.size.width
let height = image.size.height
DispatchQueue.main.async {
if width > height {
// Landscape image
self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
self.height = self.width/width * height
} else {
self.height = height > 600 ? 600 : height
self.width = self.height/height * width
}
}
}
}
用法:
GeometryReader { geometry in
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
将必须通过传入 UIImage 来更新 ContentView 的声明方式:
ContentView(image: UIImage(named: "image0")!)
所以我一直在尝试弄清楚如何在 SwiftUI 中找到图像的高度,但没有成功。基本上我有 portrait/landscape 图像,我想以大约 600 pt 高显示纵向图像,而我想显示横向图像,因此使用图像的宽度,所以高度是任意的。话虽如此,我希望它在 GeometryReader 内部,因为我使用的偏移量使用它,这样当您向下滚动时,图像不会滚动,但如果您向上滚动,它会滚动。我不相信我可以分享图片,但无论如何,这应该是足以 运行 成功的代码!
struct ContentView: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var backButton: some View {
Button(action: {
withAnimation {
self.mode.wrappedValue.dismiss()
}
}) {
Image(systemName: "chevron.left.circle.fill")
.opacity(0.8)
.font(.system(size: 30))
.foregroundColor(.black)
.background(Color.gray.mask(Image(systemName: "chevron.left").offset(x: 9.4, y: 7.6)))
}
}
var body: some View {
ScrollView(showsIndicators: false) {
GeometryReader { geometry in
Image("image1")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: UIScreen.main.bounds.width, minHeight: 350, maxHeight: 600, alignment: .top)
.clipped()
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
}
.frame(minWidth: UIScreen.main.bounds.width, maxWidth: UIScreen.main.bounds.width, minHeight: 350, idealHeight: 600, maxHeight: 600)
//Message
VStack(alignment: .leading) {
Text("\(07/22/20) - Day \(1)")
.font(.body)
.fontWeight(.light)
.foregroundColor(Color.gray)
.padding(.leading)
Text("what I Love)
.font(.title)
.fontWeight(.bold)
.padding([.leading, .bottom])
Text("paragraph")
.padding([.leading, .bottom, .trailing])
}
}
.edgesIgnoringSafeArea(.all)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton)
}
}
如有任何帮助,我们将不胜感激!
编辑: 这里有两张图片供参考 - 抱歉,我没有意识到你能做到,虽然我早该想到!
如果我没理解错的话,您想要图像的大小以便可以在它自己的框架中使用它的尺寸?您可以创建一个函数,该函数接受图像名称和 returns 您想要的图像,同时还为可以在框架中使用的 width
和 height
设置 @State
变量。
@State var width: CGFloat = 0
@State var height: CGFloat = 0
func image(_ name: String) -> UIImage {
let image = UIImage(named: name)!
let width = image.size.width
let height = image.size.height
DispatchQueue.main.async {
if width > height {
// Landscape image
// Use screen width if < than image width
self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
// Scale height
self.height = self.width/width * height
} else {
// Portrait
// Use 600 if image height > 600
self.height = height > 600 ? 600 : height
// Scale width
self.width = self.height/height * width
}
}
return image
}
用法:
GeometryReader { geometry in
Image(uiImage: image("image1"))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
编辑:添加了 DispatchQueue.main.async
块作为 'Modifying state during view update' 警告的快速修复。可行,但可能不是解决它的绝对最佳方法。将图像放入它自己的 @State
并在视图的 onAppear
方法中设置它可能更好。
编辑 2:将图像移动到它自己的 @State
var 中,我认为这是一个更好的解决方案,因为它会使视图更易于重用,因为您可以传递图像而不是硬编码图像的名称在视图中。
@State var image: UIImage {
didSet {
let width = image.size.width
let height = image.size.height
DispatchQueue.main.async {
if width > height {
// Landscape image
self.width = width > UIScreen.main.bounds.width ? UIScreen.main.bounds.width : width
self.height = self.width/width * height
} else {
self.height = height > 600 ? 600 : height
self.width = self.height/height * width
}
}
}
}
用法:
GeometryReader { geometry in
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
.overlay(
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .white]), startPoint: .center, endPoint: .bottom))
)
.offset(y: geometry.frame(in: .global).minY > 0 ? -geometry.frame(in: .global).minY : 0)
将必须通过传入 UIImage 来更新 ContentView 的声明方式:
ContentView(image: UIImage(named: "image0")!)