struct ContentView: View {
@StateObject var viewModel = ContentViewModel()
var body: some View {
NavigationView {
ScrollView {
LazyVStack {
ForEach(Array(viewModel.items.enumerated()), id: \.offset) { offset, item in
// MARK: - Cell
NavigationLink {
DetailItemView(item: item, offset: offset, delegate: viewModel)
} label: {
Cell(item: item, offset: 0)
}
}
}
}
}
}
@ViewBuilder
func Cell(item: Item, offset: Int) -> some View {
HStack(spacing: 16) {
Circle()
.frame(width: 50, height: 50)
.foregroundColor(item.color)
Spacer()
Text("\(String(item.id.prefix(8)))")
.font(.body)
Image(systemName: item.isLiked ? "heart.fill" : "heart")
.resizable()
.frame(width: 20, height: 20)
.foregroundColor(item.isLiked ? .red : .black)
}
.padding(.horizontal, 16)
.frame(maxWidth: .infinity)
.frame(height: 80)
}
}
class ContentViewModel: ObservableObject, ItemDelegate {
@Published var items: [Item] = []
init() { getItems() }
func getItems() {
for _ in 1...30 {
DispatchQueue.main.async { [weak self] in
self?.items.append(Item.init())
}
}
}
func didTapIsLike(offset: Int) {
DispatchQueue.main.async { [weak self] in
self?.items[offset].isLiked.toggle()
}
}
}
struct DetailItemView: View {
@State var item: Item
let offset: Int
weak var delegate: ItemDelegate?
init(item: Item, offset: Int, delegate: ItemDelegate? = nil) {
self._item = State(wrappedValue: item)
self.offset = offset
self.delegate = delegate
}
var body: some View {
VStack {
Image(systemName: item.isLiked ? "heart.fill" : "heart")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(item.isLiked ? .red : .black)
.onTapGesture { didTapItem() }
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(item.color.opacity(0.3))
}
func didTapItem() {
item.isLiked.toggle()
delegate?.didTapIsLike(offset: offset)
}
}
protocol ItemDelegate: AnyObject {
func didTapIsLike(offset: Int)
}
struct Item: Identifiable, Hashable {
let id = UUID().uuidString
let color = Color.random
var isLiked = Bool.random()
}
extension Color {
static var random: Color {
return Color(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}