1

My code looks like this:

    ZStack {
        
        NetworkImage(url: url)
        VStack(alignment: .trailing, spacing: 5) {
            Spacer()
            Text("this is my quite long title here")
                    .font(.title)
                    .bold()
                    .foregroundColor(.white)
                    .lineLimit(nil)
                    .multilineTextAlignment(.trailing)
            Text("subtitle this is my long long subtitle to create multiply lines")
                    .font(.caption)
                    .foregroundColor(.white)
                    .lineLimit(nil)
                    .multilineTextAlignment(.trailing)
        }
        .padding()
    }

struct NetworkImage: View {
    let url: URL?
    var body: some View {
        if let url = url, let imageData = try? Data(contentsOf: url), let uiImage = UIImage(data: imageData) {
            Image(uiImage: uiImage)
                .resizable()
                .scaledToFill()
        }
    }
}

But this looks bad and it is not what I need t achieve.

I need to make it aligned to the right and to the bottom with some padding from the edges. That is all. How can I do this?

enter image description here enter image description here

After update from @user1046037 answer it looks like:

enter image description here enter image description here

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358

2 Answers2

2

Code Changes:

1. ZStack Alignment

ZStack(alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {

2. Crop in the center

In NetworkImage, center crop (code provided) in the image extension.

Thanks to @vacawama How to center crop an image in SwiftUI

Complete Code:

struct ContentView: View {
    var body: some View {
        ZStack(alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {
            
            NetworkImage(url: URL(string: "https://unsplash.com/photos/KZv3Rb_OIXI/download?force=true"))
            VStack(alignment: .trailing, spacing: 5) {
                Spacer()
                Text("this is my quite long title here")
                        .font(.title)
                        .bold()
                        .foregroundColor(.white)
                        .lineLimit(nil)
                        .multilineTextAlignment(.trailing)
                Text("subtitle this is my long long subtitle to create multiply lines")
                        .font(.caption)
                        .foregroundColor(.white)
                        .lineLimit(nil)
                        .multilineTextAlignment(.trailing)
            }
            .padding()
        }
    }
}

//Center Crop
extension Image {
    func centerCropped() -> some View {
        GeometryReader { geo in
            self
            .resizable()
            .scaledToFill()
            .frame(width: geo.size.width, height: geo.size.height)
            .clipped()
        }
    }
}

struct NetworkImage: View {
    let url: URL?
    var body: some View {
        if let url = url, let imageData = try? Data(contentsOf: url), let uiImage = UIImage(data: imageData) {
            Image(uiImage: uiImage)
                .centerCropped()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
user1046037
  • 16,755
  • 12
  • 92
  • 138
2

The ZStack with the Image in it is the problem. The ZStack isn’t cropping the Image, it’s actually growing to fit the image and extending outside the bounds of the widget. The Text is inside that same ZStack, so it too grows to fill the available space.

Maybe this helps visualize the issue (black round-rect is the widget frame): widget content with black frame showing where its cropped

Solution

Put the image in the VStack's .background instead:

var body: some View {

    VStack(alignment: .trailing, spacing: 5) {
        Spacer()
        Text("this is my quite long title here")
            .font(.title)
            .bold()
            .foregroundColor(.white)
            .lineLimit(nil)
            .multilineTextAlignment(.trailing)
        Text("subtitle this is my long long subtitle to create multiply lines")
            .font(.caption)
            .foregroundColor(.white)
            .lineLimit(nil)
            .multilineTextAlignment(.trailing)
    }
    .padding()
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(NetworkImage(url: url))

}

struct NetworkImage: View {
    let url: URL?
    var body: some View {
        if let url = url, let imageData = try? Data(contentsOf: url), let uiImage = UIImage(data: imageData) {
            Image(uiImage: uiImage)
                .resizable()
                .scaledToFill()
        }
    }
}
Adam
  • 4,405
  • 16
  • 23
  • Thank you for your answer, but the image fits to the view. Doesnt fill a whole space... Is there anything to set contentMode like `.aspectFill` instead of `.aspectFit` – Bartłomiej Semańczyk Jan 16 '21 at 18:11
  • Are you using the `NetworkImage` from your original post, with the `scaledToFill`? (I updated my answer to clarify what NetworkImage is) – Adam Jan 16 '21 at 18:55