Reputation: 212
I have a project that contains a list where I want to use a blurred async image as the background for each list row. This works fine when I have 2 or less list rows, but when I add a 3rd it messes up the entire UI. I have no idea why it's doing this and it's pretty difficult trying to search for such a specific issue. My code for this view and some screenshots are below. Thanks in advance!
import SwiftUI
struct UserView: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(sortDescriptors: []) var users: FetchedResults<CachedUser>
@FetchRequest(sortDescriptors: []) var reviews: FetchedResults<CachedReview>
@State private var showingAddUserScreen = false
@State private var showingAddReview = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(users, id: \.self) { user in
Section(user.wrappedUsername) {
ForEach(user.reviewsArray, id: \.self) { review in
NavigationLink {
DetailView(review: review)
} label: {
HStack {
AsyncImage(url: URL(string: review.wrappedArtwork)) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 50, height: 50)
} placeholder: {
Color.gray.blur(radius: 30)
}
VStack(alignment: .leading, spacing: 2) {
Text(review.wrappedAlbumTitle)
.fontWeight(.bold)
.foregroundColor(.yellow)
Text(review.wrappedAlbumArtist)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
}
}
}
.listRowBackground(
AsyncImage(url: URL(string: review.wrappedArtwork)) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.blur(radius: 30)
} placeholder: {
Color.gray.blur(radius: 30)
}
)
}
.onDelete(perform: deleteReview)
}
}
.onDelete(perform: deleteUser)
}
}
.navigationTitle("Critiq")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showingAddUserScreen.toggle()
} label: {
Label("Add User", systemImage: "plus")
}
}
ToolbarItem(placement: .navigationBarLeading) {
Button {
showingAddReview.toggle()
} label: {
Label("Add User", systemImage: "plus.square")
}
}
}
.sheet(isPresented: $showingAddUserScreen) {
AddUserView()
}
.sheet(isPresented: $showingAddReview) {
AddReviewView()
}
}
}
func deleteUser(at offsets: IndexSet) {
for offset in offsets {
let user = users[offset]
moc.delete(user)
}
try? moc.save()
}
func deleteReview(at offsets: IndexSet) {
for offset in offsets {
let review = reviews[offset]
moc.delete(review)
}
try? moc.save()
}
}
2 or less list items VS 3 or more
Upvotes: 0
Views: 88
Reputation: 2907
I was curious about this one as you mentioned it broke when you added a third item, two items would make up a header and footer, a third would be an item...then I started to play around with it.
If you remove the .clipped
code from my sample you can see that when there are three or more items, the content in the middle bleeds out.
If you keep the clipped it doesn't look as nice. You could probably get the effect you're after with some other combination of clipping/masking/list styles
import SwiftUI
struct Review {
let wrappedArtwork: String
let wrappedAlbumTitle: String
let wrappedAlbumArtist: String
}
extension Review: Hashable {
static func == (lhs: Review, rhs: Review) -> Bool {
lhs.wrappedAlbumTitle == rhs.wrappedAlbumTitle &&
lhs.wrappedAlbumArtist == rhs.wrappedAlbumArtist
}
func hash(into hasher: inout Hasher) {
hasher.combine(wrappedAlbumTitle)
hasher.combine(wrappedAlbumArtist)
}
}
struct User {
let wrappedUsername: String
let reviewsArray: [Review]
}
extension User: Hashable {
static func == (lhs: User, rhs: User) -> Bool {
lhs.wrappedUsername == rhs.wrappedUsername
}
func hash(into hasher: inout Hasher) {
hasher.combine(wrappedUsername)
}
}
class UserObject: ObservableObject {
@Published var users: [User] = []
init(users: [User]) {
self.users = users
}
}
struct UserView: View {
@EnvironmentObject var userObject: UserObject
@State private var showingAddUserScreen = false
@State private var showingAddReview = false
var body: some View {
NavigationView {
VStack {
List {
ForEach(userObject.users, id: \.self) { user in
Section(user.wrappedUsername) {
ForEach(user.reviewsArray, id: \.self) { review in
NavigationLink {
EmptyView()
} label: {
HStack {
AsyncImage(url: URL(string: review.wrappedArtwork)) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 50, height: 50)
.clipped()
} placeholder: {
Color.gray.blur(radius: 30)
}
VStack(alignment: .leading, spacing: 2) {
Text(review.wrappedAlbumTitle)
.fontWeight(.bold)
.foregroundColor(.yellow)
Text(review.wrappedAlbumArtist)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
}
}
}
.listRowBackground(
AsyncImage(url: URL(string: review.wrappedArtwork)) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.blur(radius: 30)
.clipped()
} placeholder: {
Color.gray.blur(radius: 30)
}
)
}
}
}
}
}
.navigationTitle("Critiq")
}
}
}
struct UserView_Previews: PreviewProvider {
static var review1 = Review(wrappedArtwork: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", wrappedAlbumTitle: "my title 1", wrappedAlbumArtist: "my artist")
static var review2 = Review(wrappedArtwork: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", wrappedAlbumTitle: "my title 2", wrappedAlbumArtist: "my artist")
static var review3 = Review(wrappedArtwork: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", wrappedAlbumTitle: "my title 3", wrappedAlbumArtist: "my artist")
static var review4 = Review(wrappedArtwork: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", wrappedAlbumTitle: "my title 4", wrappedAlbumArtist: "my artist")
static var fourObjects = UserObject(users: [User(wrappedUsername: "Bob", reviewsArray: [review1, review2, review3, review4])])
static var threeObjects = UserObject(users: [User(wrappedUsername: "Bob", reviewsArray: [review1, review2, review3])])
static var twoObjects = UserObject(users: [User(wrappedUsername: "Bob", reviewsArray: [review1, review2])])
static var previews: some View {
Group {
UserView()
.environmentObject(twoObjects)
.previewDisplayName("two items")
UserView()
.environmentObject(threeObjects)
.previewDisplayName("three items")
UserView()
.environmentObject(fourObjects)
.previewDisplayName("four items")
}
}
}
Upvotes: 1