Realizzare una sezione commenti professionale richiede molto più di una semplice lista piatta: gli utenti si aspettano di poter rispondere a commenti specifici, visualizzare un albero di risposte indentato con frecce grafiche, mettere like sia ai propri commenti che a quelli altrui e avere una barra di input contestuale con il tag "Rispondendo a @username".
1. Il Modello Dati Ricorsivo in Swift
In SwiftUI, modelliamo il commento come una struttura gerarchica che supporta figli nidificati:
import Foundation
public struct CommentItem: Identifiable, Codable {
public let id: Int
public let userId: Int
public let userName: String
public let userAvatarUrl: String?
public let content: String
public var likesCount: Int
public var isLikedByMe: Bool
public let parentId: Int?
public let replyToUserName: String?
public let createdAt: Date
public var replies: [CommentItem] = []
}
2. Rendering Grafico dell'Albero con Frecce e Banner Contestuale
Per dare l'aspetto moderno e pulito tipico di app come Threads o TikTok, le risposte di secondo livello vengono renderizzate con una freccia angolare curva (arrow.turn.down.right) e un margine sinistro dedicato:
import SwiftUI
struct CommentRowView: View {
let comment: CommentItem
let onReplyTap: (CommentItem) -> Void
let onLikeTap: (CommentItem) -> Void
var body: some View {
VStack(alignment: .leading, spacing: 8) {
// Commento Principale
singleCommentCard(comment: comment, isReply: false)
// Risposte Nidificate (Replies)
if !comment.replies.isEmpty {
VStack(spacing: 6) {
ForEach(comment.replies) { reply in
HStack(alignment: .top, spacing: 8) {
Image(systemName: "arrow.turn.down.right")
.font(.system(size: 11, weight: .bold))
.foregroundStyle(Color.secondary.opacity(0.6))
.padding(.top, 6)
singleCommentCard(comment: reply, isReply: true)
}
.padding(.leading, 20)
}
}
}
}
}
private func singleCommentCard(comment: CommentItem, isReply: Bool) -> some View {
HStack(alignment: .top, spacing: 10) {
Circle()
.fill(Color.gray.opacity(0.3))
.frame(width: isReply ? 28 : 34, height: isReply ? 28 : 34)
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(comment.userName)
.font(.system(size: 13, weight: .bold))
if let replyTo = comment.replyToUserName {
Text("▸ @\(replyTo)")
.font(.system(size: 11, weight: .semibold))
.foregroundStyle(Color.blue)
}
Spacer()
Text("2m")
.font(.system(size: 10))
.foregroundStyle(Color.secondary)
}
Text(comment.content)
.font(.system(size: 13))
HStack(spacing: 16) {
Button("Rispondi") {
onReplyTap(comment)
}
.font(.system(size: 11, weight: .bold))
.foregroundStyle(Color.blue)
Button {
onLikeTap(comment)
} label: {
HStack(spacing: 3) {
Image(systemName: comment.isLikedByMe ? "heart.fill" : "heart")
.foregroundStyle(comment.isLikedByMe ? Color.red : Color.secondary)
Text("\(comment.likesCount)")
.font(.system(size: 11))
}
}
}
.padding(.top, 2)
}
}
.padding(10)
.background(Color(.secondarySystemBackground))
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}
Vuoi integrare un feed di commenti interattivo nella tua app?
Creiamo componenti UI SwiftUI fluidi con architetture serverless e database relazionali ad alte prestazioni.