如何在 SwiftUI 中以相同的尺寸显示不同屏幕尺寸的屏幕?
How can I show in SwiftUI a screen in different screen sizes with the same measures?
我的应用在不同屏幕尺寸下出现问题。我举了一个小例子来说明问题。
我有一个屏幕,左边是文本和按钮,右边是图像。在这之后,在 zstack 中,我有相同的图像更大,并且在该图像上有一层不透明度 0.5。
问题是我使用的是相对于屏幕的测量结果不同。在所附的图片中,您可以看到差异。
这是代码。
struct Screen2: View {
var body: some View {
VStack {
ZStack {
ZStack {
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: .init(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.width)))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.cornerRadius(0)
Color.black
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.opacity(0.5)
}
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 5, alignment: .top)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: CGSize.init(width: UIScreen.main.bounds.width / 4, height: UIScreen.main.bounds.height / 4)))
}
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
}
func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
var newSize:CGSize
if (widthRatio > heightRatio)
{
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
}
else
{
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
任何人都可以帮助我在每个屏幕尺寸下以相同的方式显示结果吗?
谢谢
- 您正在将封面大小调整为一个
targetSize
,然后使用 .frame
设置另一个大小,然后再向容器 ZStack
添加一个框架。你为什么要那样做?
- 当更改图像框架并将
contentMode
设置为 .fill
时,它将在其框架中居中,但图像的其余部分将在框架外可见。你可以在这个例子中看到:
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.overlay(Rectangle().stroke(lineWidth: 5).foregroundColor(.red))
这可以用 .clipped()
修饰符修复。如果您熟悉
,它与 UIKit 上的 clipsToBounds
相同
- 当您将
edgesIgnoringSafeArea
应用于 VStack
中的一个项目时,它的工作方式类似于 offset
修饰符,这意味着下一个项目不会紧随其后。您需要将 edgesIgnoringSafeArea
应用于整个 VStack
,并且如果需要,您可以禁用 if .edgesIgnoringSafeArea([])
用于需要安全区域插入 的项目
- 在将图像传递给
Image
之前无需调整图像大小,尤其是您不想在视图生成器函数中执行此操作,因为每次更新此视图时都会重新计算。通常应用所需的修饰符完全足以获得所需的结果,让 SwiftUI 为您优化它:
VStack(spacing: 0) {
ZStack(alignment: .bottom) {
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
ZStack {
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.clipped()
Color.black
.opacity(0.5)
}
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image("cover")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.width / 4)
}
.edgesIgnoringSafeArea([])
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
.edgesIgnoringSafeArea(.all)
结果:
我的应用在不同屏幕尺寸下出现问题。我举了一个小例子来说明问题。 我有一个屏幕,左边是文本和按钮,右边是图像。在这之后,在 zstack 中,我有相同的图像更大,并且在该图像上有一层不透明度 0.5。
问题是我使用的是相对于屏幕的测量结果不同。在所附的图片中,您可以看到差异。
这是代码。
struct Screen2: View {
var body: some View {
VStack {
ZStack {
ZStack {
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: .init(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.width)))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.cornerRadius(0)
Color.black
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.opacity(0.5)
}
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 5, alignment: .top)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: CGSize.init(width: UIScreen.main.bounds.width / 4, height: UIScreen.main.bounds.height / 4)))
}
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
}
func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
var newSize:CGSize
if (widthRatio > heightRatio)
{
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
}
else
{
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
任何人都可以帮助我在每个屏幕尺寸下以相同的方式显示结果吗?
谢谢
- 您正在将封面大小调整为一个
targetSize
,然后使用.frame
设置另一个大小,然后再向容器ZStack
添加一个框架。你为什么要那样做? - 当更改图像框架并将
contentMode
设置为.fill
时,它将在其框架中居中,但图像的其余部分将在框架外可见。你可以在这个例子中看到:
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.overlay(Rectangle().stroke(lineWidth: 5).foregroundColor(.red))
这可以用 .clipped()
修饰符修复。如果您熟悉
clipsToBounds
相同
- 当您将
edgesIgnoringSafeArea
应用于VStack
中的一个项目时,它的工作方式类似于offset
修饰符,这意味着下一个项目不会紧随其后。您需要将edgesIgnoringSafeArea
应用于整个VStack
,并且如果需要,您可以禁用 if.edgesIgnoringSafeArea([])
用于需要安全区域插入 的项目
- 在将图像传递给
Image
之前无需调整图像大小,尤其是您不想在视图生成器函数中执行此操作,因为每次更新此视图时都会重新计算。通常应用所需的修饰符完全足以获得所需的结果,让 SwiftUI 为您优化它:
VStack(spacing: 0) {
ZStack(alignment: .bottom) {
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
ZStack {
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.clipped()
Color.black
.opacity(0.5)
}
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image("cover")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.width / 4)
}
.edgesIgnoringSafeArea([])
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
.edgesIgnoringSafeArea(.all)
结果: