I’m having problems with my app with different screen sizes. I made a little example to show the problem. I have a screen with a text and a button on the left and an image on the right. Behind this, in zstack, I have the same image bigger and a layer over this image with opacity 0.5.
The problem is that I’m using measures relative to the screen and the result is different. In the image attached you can see the differences.
This is the code.
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!
}
}
Anyone can help me to show the result in the same way in every screen size?
Thank you
targetSize
, and then setting an other size using .frame
, and then adding one more frame to container ZStack
. Why would you do that?contentMode
set to .fill
, it's gonna be centered in its frame but rest of the image will be visible out of the frame. You can see this in this example: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))
This can be fixed with .clipped()
modifier. It's same as clipsToBounds
on UIKit if you're familiar with that
edgesIgnoringSafeArea
to one item in VStack
, it works like offset
modifier, which means that next item won't be right after. You need to apply edgesIgnoringSafeArea
to whole VStack
, and, if needed, you can than disable if .edgesIgnoringSafeArea([])
for items that needs safe area insetImage
, especially you don't want to do that inside view builder function, because this gonna be re-calculated each time you update this view. Usually applying needed modifiers is totally enough to get needed result, let SwiftUI optimize it for your: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)
Result: