Shweta
Shweta

Reputation: 1247

How to add background image to complete view in SwiftUI

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

Answers (7)

Mojtaba Hosseini
Mojtaba Hosseini

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.

💡Important note:

Use minWidth for the frame of the image to prevent the overflowing of other views inside the ZStack.

Upvotes: 57

Dinesh Kumar
Dinesh Kumar

Reputation: 151

struct LoginView: View {
    var body: some View {
        Image("imageName")
            .resizable()
            .ignoresSafeArea(.all)
    }
}

Upvotes: -1

Mark
Mark

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

Simone Pistecchia
Simone Pistecchia

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

Antonio Lopes
Antonio Lopes

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

Rohit Makwana
Rohit Makwana

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

Tobias Hesselink
Tobias Hesselink

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

Related Questions