import SwiftUI // MARK: - 简化的卡片组件 struct SimpleCardView: View { let content: AnyView let padding: EdgeInsets let cornerRadius: CGFloat let shadowColor: Color let shadowRadius: CGFloat let shadowOffset: CGSize let backgroundColor: Color init( padding: EdgeInsets = EdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16), cornerRadius: CGFloat = 12, shadowColor: Color = .black.opacity(0.1), shadowRadius: CGFloat = 8, shadowOffset: CGSize = CGSize(width: 0, height: 4), backgroundColor: Color = Color(.systemBackground), @ViewBuilder content: () -> some View ) { self.padding = padding self.cornerRadius = cornerRadius self.shadowColor = shadowColor self.shadowRadius = shadowRadius self.shadowOffset = shadowOffset self.backgroundColor = backgroundColor self.content = AnyView(content()) } var body: some View { content .padding(padding) .background(backgroundColor) .cornerRadius(cornerRadius) .shadow( color: shadowColor, radius: shadowRadius, x: shadowOffset.width, y: shadowOffset.height ) } } // MARK: - 预定义的卡片样式 extension SimpleCardView { static func standard( @ViewBuilder content: () -> Content ) -> SimpleCardView { SimpleCardView(content: content) } static func elevated( @ViewBuilder content: () -> Content ) -> SimpleCardView { SimpleCardView( shadowColor: .black.opacity(0.15), shadowRadius: 12, shadowOffset: CGSize(width: 0, height: 6), content: content ) } static func subtle( @ViewBuilder content: () -> Content ) -> SimpleCardView { SimpleCardView( shadowColor: .black.opacity(0.05), shadowRadius: 4, shadowOffset: CGSize(width: 0, height: 2), content: content ) } static func compact( @ViewBuilder content: () -> Content ) -> SimpleCardView { SimpleCardView( padding: EdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12), cornerRadius: 8, content: content ) } static func large( @ViewBuilder content: () -> Content ) -> SimpleCardView { SimpleCardView( padding: EdgeInsets(top: 24, leading: 24, bottom: 24, trailing: 24), cornerRadius: 16, content: content ) } } // MARK: - 信息卡片组件 struct InfoCard: View { let title: String let subtitle: String? let icon: String? let iconColor: Color let content: String let actionTitle: String? let action: (() -> Void)? init( title: String, subtitle: String? = nil, icon: String? = nil, iconColor: Color = .blue, content: String, actionTitle: String? = nil, action: (() -> Void)? = nil ) { self.title = title self.subtitle = subtitle self.icon = icon self.iconColor = iconColor self.content = content self.actionTitle = actionTitle self.action = action } var body: some View { SimpleCardView.standard { VStack(alignment: .leading, spacing: 12) { // 标题行 HStack { if let icon = icon { Image(systemName: icon) .font(.title2) .foregroundColor(iconColor) } VStack(alignment: .leading, spacing: 2) { Text(title) .font(.headline) .foregroundColor(.primary) if let subtitle = subtitle { Text(subtitle) .font(.caption) .foregroundColor(.secondary) } } Spacer() } // 内容 Text(content) .font(.body) .foregroundColor(.primary) .lineLimit(nil) // 操作按钮 if let actionTitle = actionTitle, let action = action { Button(action: action) { Text(actionTitle) .font(.subheadline) .fontWeight(.medium) .foregroundColor(iconColor) } } } } } } // MARK: - 统计卡片组件 struct StatCard: View { let title: String let value: String let subtitle: String? let icon: String? let iconColor: Color let trend: Trend? enum Trend { case up(String) case down(String) case neutral(String) } init( title: String, value: String, subtitle: String? = nil, icon: String? = nil, iconColor: Color = .blue, trend: Trend? = nil ) { self.title = title self.value = value self.subtitle = subtitle self.icon = icon self.iconColor = iconColor self.trend = trend } var body: some View { SimpleCardView.standard { VStack(alignment: .leading, spacing: 12) { // 标题和图标 HStack { if let icon = icon { Image(systemName: icon) .font(.title2) .foregroundColor(iconColor) } Text(title) .font(.subheadline) .foregroundColor(.secondary) Spacer() } // 数值 Text(value) .font(.title) .fontWeight(.bold) .foregroundColor(.primary) // 副标题和趋势 HStack { if let subtitle = subtitle { Text(subtitle) .font(.caption) .foregroundColor(.secondary) } Spacer() if trend != nil { HStack(spacing: 4) { Image(systemName: trendIcon) .font(.caption) .foregroundColor(trendColor) Text(trendValue) .font(.caption) .foregroundColor(trendColor) } } } } } } private var trendIcon: String { switch trend { case .up: return "arrow.up" case .down: return "arrow.down" case .neutral: return "minus" case .none: return "" } } private var trendColor: Color { switch trend { case .up: return .green case .down: return .red case .neutral: return .orange case .none: return .clear } } private var trendValue: String { switch trend { case .up(let value), .down(let value), .neutral(let value): return value case .none: return "" } } } #Preview { VStack(spacing: 20) { // 标准卡片 SimpleCardView.standard { VStack(alignment: .leading, spacing: 12) { Text("标准卡片") .font(.headline) Text("这是一个标准样式的卡片组件") .font(.body) } } // 信息卡片 InfoCard( title: "提示信息", subtitle: "重要提醒", icon: "info.circle", content: "这是一个信息卡片,用于显示重要的提示信息。", actionTitle: "了解更多", action: {} ) // 统计卡片 StatCard( title: "总用户数", value: "1,234", subtitle: "本月新增 123", icon: "person.3", trend: .up("+12%") ) // 紧凑卡片 SimpleCardView.compact { Text("紧凑卡片") .font(.headline) } } .padding() }