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.
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:
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:
I'm stuck...
Thank you in advance!
CodePudding user response:
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.
CodePudding user response:
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()
}
}
}
}
}