skip to Main Content

In the wonderful world of SwiftUI, I have a View that I use as a cell. I intend to reproduce the Layout of a previous application of mine, with Autolayout, not SwiftUI, in which the background image filled the entire cell, adjusting to the width and losing pieces of image above and below.

enter image description here

In my new app, the code in SwiftUI is the following:

struct CharacterRow2: View {
    var character: Character 
    var body: some View {
        Text(character.name)
            .font(Font.custom(avengeanceHeroicAvengerNormal, size: 30))
            .foregroundColor(.white)
            .baselineOffset(-10)
            .shadow(color: .black, radius: 1, x: -1, y: 1)
            .frame(width: UIScreen.main.bounds.width, height: 140)
            .background {
                WebImage(url: extractImage(data: character.thumbnail))
                    .resizable()
                    .frame(width: UIScreen.main.bounds.width, height: 150)
            }
    }
}

With this code, my app looks like this:

enter image description here

I tried to add scaledToFill():

                WebImage(url: extractImage(data: character.thumbnail))
                    .resizable()
                    .scaledToFill()
                    .frame(width: UIScreen.main.bounds.width, height: 150)

But this is the result:

enter image description here

I’m stuck…

Thank you in advance!

2

Answers


  1. In your last example the images are overlaying each other. This is due to calling scaleToFill(). The images are now ignoring their frame boundaries regarding the height. Adding .clipped solves the problem.

    struct CharacterRow2: View {
        var character: String
        var body: some View {
            Text(character)
                .font(.largeTitle)
                .foregroundColor(.white)
                .baselineOffset(-10)
                .shadow(color: .black, radius: 1, x: -1, y: 1)
                .frame(width: UIScreen.main.bounds.width, height: 140)
                .background {
                    Image(character)
                        .resizable()
                        .scaledToFill()
                        .frame(width: UIScreen.main.bounds.width, height: 150)
                        .clipped() // <-- Add this
                }
        }
    }
    

    It seems this will work only with a ForEach inside a ScrollView. Using a List seems to breack the vertical frame boundary.

    struct ContentView: View{
        
        let content = ["1.jpg", "2.jpg", "3.jpg" ]
        
        var body: some View{
            //These look really weird
    //        List(content, id: .self){ name in
    //            CharacterRow2(character: name)
    //        }
            
    //        List{
    //            VStack{
    //                ForEach(content, id: .self){ name in
    //                    CharacterRow2(character: name)
    //                }
    //            }
    //        }
            
            //working
            ScrollView{
                VStack{
                    ForEach(content, id: .self){ name in
                        CharacterRow2(character: name)
                            .padding()
                    }
                }
            }
        }
    }
    

    Result:
    enter image description here

    Login or Signup to reply.
  2. In this case, you are simply using too many frames. And using them incorrectly. You should avoid using UIScreen.main.bounds in SwiftUI, especially in something like a view cell. By doing this, the cell will not behave properly with other views, and can cause UI issues that would be difficult to trace.

    The simplest way to get the behavior you want is this:

        Text(character.name)
            .font(.largeTitle)
            .foregroundColor(.white)
            .baselineOffset(-10)
            .shadow(color: .black, radius: 1, x: -1, y: 1)
            .frame(height: 140)
            .frame(maxWidth: .infinity) // use .infinity for max width to make it
                                        // as large as the space offered by the
                                        // parent view
            .background {
                WebImage(url: extractImage(data: character.thumbnail))
                    .resizable()
                    // .frame(width: UIScreen.main.bounds.width, height: 150) <-- Remove this frame altogether
                    .scaledToFill()
            }
            .clipped // This keeps the image from being larger than the frame
    

    This will size to be as wide as the parent view allows it to be. Leaving the UIScreen.main.bounds.width could cause it to be larger than the parent view and cause partial eclipsing.

    Example

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search