Reputation: 1247
I am new to SwiftUI. I want to design a custom view with few controls and a background image. The background image should cover the complete view. It should look like a watermark for the screen. How can I achieve this using SwiftUI?
Upvotes: 28
Views: 38754
Reputation: 120052
Use ZStack
but Don't use UIScreen
:
var body: some View {
ZStack {
Image("BG")
.resizable()
.scaledToFill()
.frame(minWidth: 0) // 👈 This will keep other views (like a large text) in the frame
.edgesIgnoringSafeArea(.all)
Text("Long multiline text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer eu nulla id lorem pulvinar tincidunt. Donec ut pharetra lacus, et consectetur neque. Etiam quis congue purus. Praesent eu tempus quam, at tristique elit. Ut non urna mi. Maecenas nec arcu neque. Mauris iaculis quam at sapien luctus tristique.")
.padding()
}
}
Using UIScreen
will lead your app to undesired behavior if you are supporting multiscreen app, resizable windows, multiwindow app, etc.
Use minWidth
for the frame of the image to prevent the overflowing of other views inside the ZStack
.
Upvotes: 57
Reputation: 151
struct LoginView: View {
var body: some View {
Image("imageName")
.resizable()
.ignoresSafeArea(.all)
}
}
Upvotes: -1
Reputation: 18234
The answer of Mojtaba is incomplete. The problem is the bounding box of the image can exceed the screen leading to undesired behavior. To correct this we need to add .frame
to the mix. This will make sure the image is as large as the screen and fixes our problem.
struct BackgroundView: View {
var body: some View {
GeometryReader { proxy in
Image("Background")
.resizable()
.scaledToFill()
.frame(width: proxy.size.width, height: proxy.size.height)
.clipped()
}.ignoresSafeArea()
}
}
Upvotes: 3
Reputation: 2840
UPDATE
with iOS 15 Xcode 13.2
public extension View {
func fullBackground(imageName: String) -> some View {
return background(
Image(imageName)
.resizable()
.scaledToFill()
.edgesIgnoringSafeArea(.all)
)
}
}
use
YourView
.fullBackground(imageName: "imageName")
END UPDATE
OLD ANSWER
I prefer a @ViewBuilder
Usage:
BackgroundView(imageName: "image name") {
Text("Hello")
}
@ViewBuilder
public struct BackgroundView <Content : View> : View {
public var content : Content
public var imageName: String
public var opacity: Double
public init(imageName: String, opacity: Double=1,@ViewBuilder content: () -> Content) {
self.content = content()
self.imageName = imageName
self.opacity = opacity
}
public var body: some View {
GeometryReader { geo in
ZStack {
Image(imageName)
.resizable()
.scaledToFill()
.edgesIgnoringSafeArea(.all)
.frame(width: geo.size.width, height: geo.size.height, alignment: .center)
.opacity(opacity)
content
}
}
}
}
Upvotes: 9
Reputation: 241
Try this:
var body: some View {
ZStack {
Text("Hello")
}
.background(
Image("Background")
.resizable()
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
)
}
Upvotes: 23
Reputation: 4905
You can achieve this using ZStack
like below. You can add more control on Image
for example I added Text()
var body: some View {
ZStack{
Image("your image")
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
Text("Hello World").foregroundColor(.white).font(.system(size: 20)).bold()
}
}
You can Ignore SafeArea
using
.edgesIgnoringSafeArea(.all)
Upvotes: 0
Reputation: 1657
If you just want to use the full screen width and height, and you don't bother about the aspect ratio of the image, you can either use a geometry reader of the UIScreen size's.
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
This line of code will set the Image to the max size of the device. Depending on your parent view and device, you may need to use:
.edgesIgnoringSafeArea(.all)
This will ignore the safe area's on iPhone X devices and above.
Upvotes: 0