import SwiftUI // MARK: - 通用表单组件 struct FormView: View { let title: String? let content: Content let spacing: CGFloat let padding: EdgeInsets init( title: String? = nil, spacing: CGFloat = 16, padding: EdgeInsets = EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20), @ViewBuilder content: () -> Content ) { self.title = title self.spacing = spacing self.padding = padding self.content = content() } var body: some View { ScrollView { VStack(spacing: spacing) { if let title = title { HStack { Text(title) .font(.title2) .fontWeight(.semibold) .foregroundColor(.primary) Spacer() } } content } .padding(padding) } .background(Color(.systemGroupedBackground)) } } // MARK: - 表单分组组件 struct FormGroup: View { let title: String? let content: Content let spacing: CGFloat init( title: String? = nil, spacing: CGFloat = 12, @ViewBuilder content: () -> Content ) { self.title = title self.spacing = spacing self.content = content() } var body: some View { VStack(alignment: .leading, spacing: spacing) { if let title = title { HStack { Text(title) .font(.headline) .foregroundColor(.primary) Spacer() } } content } .padding() .background(Color(.systemBackground)) .cornerRadius(12) .shadow(color: .black.opacity(0.05), radius: 2, x: 0, y: 1) } } // MARK: - 表单行组件 struct FormRow: View { let title: String let isRequired: Bool let content: Content let icon: String? init( title: String, isRequired: Bool = false, icon: String? = nil, @ViewBuilder content: () -> Content ) { self.title = title self.isRequired = isRequired self.icon = icon self.content = content() } var body: some View { VStack(alignment: .leading, spacing: 8) { HStack { if let icon = icon { Image(systemName: icon) .font(.subheadline) .foregroundColor(.blue) } Text(title) .font(.subheadline) .foregroundColor(.primary) if isRequired { Text("*") .foregroundColor(.red) .font(.subheadline) } Spacer() } content } } } // MARK: - 表单操作按钮组件 struct FormActionButton: View { let title: String let action: () -> Void let isEnabled: Bool let style: ButtonStyle let icon: String? enum ButtonStyle { case primary case secondary case destructive case success } init( title: String, action: @escaping () -> Void, isEnabled: Bool = true, style: ButtonStyle = .primary, icon: String? = nil ) { self.title = title self.action = action self.isEnabled = isEnabled self.style = style self.icon = icon } var body: some View { Button(action: action) { HStack(spacing: 8) { if let icon = icon { Image(systemName: icon) .font(.system(size: 16, weight: .medium)) } Text(title) .font(.system(size: 16, weight: .semibold)) } .frame(maxWidth: .infinity) .padding(.vertical, 16) .background( RoundedRectangle(cornerRadius: 12) .fill(backgroundColor) ) .foregroundColor(foregroundColor) } .disabled(!isEnabled) .opacity(isEnabled ? 1.0 : 0.6) } private var backgroundColor: Color { switch style { case .primary: return .blue case .secondary: return Color(.systemGray5) case .destructive: return .red case .success: return .green } } private var foregroundColor: Color { switch style { case .primary, .destructive, .success: return .white case .secondary: return .primary } } } // MARK: - 预定义的表单操作按钮 extension FormActionButton { static func primary( title: String, action: @escaping () -> Void, isEnabled: Bool = true, icon: String? = nil ) -> FormActionButton { FormActionButton( title: title, action: action, isEnabled: isEnabled, style: .primary, icon: icon ) } static func secondary( title: String, action: @escaping () -> Void, isEnabled: Bool = true, icon: String? = nil ) -> FormActionButton { FormActionButton( title: title, action: action, isEnabled: isEnabled, style: .secondary, icon: icon ) } static func destructive( title: String, action: @escaping () -> Void, isEnabled: Bool = true, icon: String? = nil ) -> FormActionButton { FormActionButton( title: title, action: action, isEnabled: isEnabled, style: .destructive, icon: icon ) } static func success( title: String, action: @escaping () -> Void, isEnabled: Bool = true, icon: String? = nil ) -> FormActionButton { FormActionButton( title: title, action: action, isEnabled: isEnabled, style: .success, icon: icon ) } } #Preview { FormView(title: "sample_form".localized) { FormGroup(title: "basic_info".localized) { FormRow(title: "username".localized, isRequired: true, icon: "person") { TextField("enter_username".localized, text: .constant("")) .textFieldStyle(RoundedBorderTextFieldStyle()) } FormRow(title: "email".localized, isRequired: true, icon: "envelope") { TextField("enter_email".localized, text: .constant("")) .textFieldStyle(RoundedBorderTextFieldStyle()) .keyboardType(.emailAddress) } } FormGroup(title: "actions".localized) { FormActionButton.primary(title: "save".localized, action: {}) FormActionButton.secondary(title: "cancel".localized, action: {}) } } }