实用工具
EasyAppSwiftUI中常用的实用工具、视图修饰符、扩展、组件、公共函数等
实用工具
EasyAppSwiftUI 提供了丰富的实用工具集合,包括视图修饰符、扩展方法和工具函数,帮助您快速构建功能完整的 SwiftUI 应用。
我们会持续更新实用工具集,方便您快速构建功能完整的 SwiftUI 应用。
概览
- 12个自定义视图修饰符 - 用于身份验证、付费墙、加载状态等
- 扩展方法 - 增强 SwiftUI 视图和基础类型功能
- 工具函数 - 验证、触觉反馈、应用跳转等实用功能
- 跨版本兼容 - 支持不同 iOS 版本的兼容性处理
视图修饰符
1. 身份验证修饰符
自动管理用户身份验证状态,根据登录状态显示不同内容。
ContentView()
.modifier(AuthViewModifier())
// 或使用扩展方法
ContentView()
.showAuthView()功能特性:
- 自动检查用户登录状态
- 未登录用户显示登录/注册界面
- 已登录用户显示程序主页
- 平滑的状态转换动画
2. 付费墙修饰符
将内容锁定在付费墙后面,管理订阅验证。
// 基础用法
PremiumContentView()
.modifier(RequirePremiumViewModifier())
// 高级用法
PremiumContentView()
.requirePremium(
subscriptionType: .revenueCat,
sheetOrFullScreenCover: .sheet,
onCancelPaywall: {
print("用户取消付费")
},
onPaySuccess: {
print("付费成功")
}
)核心实现:
struct RequirePremiumViewModifier: ViewModifier {
@EnvironmentObject private var authManager: AuthManager
@State private var showPaywall = false
let subscriptionType: SubscriptionType
let sheetOrFullScreenCover: SheetOrFullScreenCover
let onCancelPaywall: () -> Void
let onPaySuccess: () -> Void
func body(content: Content) -> some View {
content
.onAppear {
showPaywall = !authManager.subscriptionActive
}
.sheet(isPresented: sheetOrFullScreenCover == .sheet ? $showPaywall : .constant(false)) {
paywallContent()
}
}
}3. 加载状态修饰符
显示全屏加载提示,带有可选的消息覆盖层。
@State private var isLoading = false
ContentView()
.modifier(FullScreenToastViewModifier(
isPresenting: $isLoading,
message: "正在处理您的请求...",
backgroundColor: Color.black.opacity(0.7)
))
// 或使用扩展方法
ContentView()
.fullScreenLoading(isPresenting: $isLoading)4. 闪光效果修饰符
为视图添加动画闪光效果,常用于加载状态。
LoadingView()
.modifier(ShimmerViewModifier(duration: 2.0, autoreverse: true))
// 或使用扩展方法
LoadingView()
.shimmering(enable: true, duration: 1.5)5. 键盘管理修饰符
在用户拖拽时自动收起键盘。
FormView()
.modifier(ResignKeyboardOnDragGesture())
// 或使用扩展方法
FormView()
.dismissKeyboard()扩展方法
颜色扩展
支持从十六进制字符串创建颜色。
extension Color {
init(hex: String) {
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int: UInt64 = 0
Scanner(string: hex).scanHexInt64(&int)
let a, r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(a, r, g, b) = (1, 1, 1, 0)
}
self.init(
.sRGB,
red: Double(r) / 255,
green: Double(g) / 255,
blue: Double(b) / 255,
opacity: Double(a) / 255
)
}
}使用示例:
let primaryColor = Color(hex: "007AFF") // 6位RGB
let redColor = Color(hex: "F00") // 3位RGB
let transparentBlue = Color(hex: "80007AFF") // 8位ARGB字符串扩展
提供字符串内容验证功能。
extension String {
var containsLetter: Bool {
let letterRegex = ".*[A-Za-z]+.*"
let passwordTest = NSPredicate(format: "SELF MATCHES %@", letterRegex)
return passwordTest.evaluate(with: self)
}
var containsNumber: Bool {
let numberRegex = ".*[0-9]+.*"
let passwordTest = NSPredicate(format: "SELF MATCHES %@", numberRegex)
return passwordTest.evaluate(with: self)
}
}使用示例:
let password = "password123"
let hasLetters = password.containsLetter // true
let hasNumbers = password.containsNumber // true日期扩展
提供用户友好的日期格式化。
extension Date {
var friendlyLocalFormat: String {
return self.formatted(date: .abbreviated, time: .omitted)
}
}使用示例:
let now = Date()
let formattedDate = now.friendlyLocalFormat // "Jan 15, 2024"视图扩展
提供丰富的视图增强功能。
加载状态
// 按钮加载状态
Button("提交") { }
.loading($isLoading)
// Toast 通知
someView.showToast($showToast, message: "操作成功", isSuccess: true)
// 全屏加载
someView.fullScreenLoading(isPresenting: $isLoading, message: "加载中...")样式和外观
// 圆角
someView.roundedCorners(radius: 12)
someView.cardRoundedCorners() // 预定义卡片圆角
someView.circle() // 圆形裁剪
// 阴影效果
someView.shadowCompat()
someView.colorSchemeShadow(
light: Color.gray.opacity(0.3),
dark: Color.white.opacity(0.1),
radius: 4
)
// 背景处理
someView.viewBackground() // 自适应系统背景交互增强
// 增强点击手势
CustomView()
.tappable {
// 点击操作
}
// Web 视图展示
someView.webViewSheet(
isPresented: $showWebView,
url: URL(string: "https://example.com"),
title: "网页标题"
)工具函数
触觉反馈引擎
提供简单的触觉反馈功能。
enum HapticsEngine {
static func impact(style: UIImpactFeedbackGenerator.FeedbackStyle = .light) {
UIImpactFeedbackGenerator(style: style).impactOccurred()
}
}使用示例:
// 轻微震动
HapticsEngine.impact(style: .light)
// 中等震动
HapticsEngine.impact(style: .medium)
// 强烈震动
HapticsEngine.impact(style: .heavy)验证工具
提供常用的输入验证功能。
enum Validate {
// 邮箱验证
static func validateEmail(_ email: String) -> Bool {
let emailPattern = #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"#
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailPattern)
return emailPredicate.evaluate(with: email)
}
// 密码长度验证
static func validatePasswordLength(_ password: String) -> Bool {
return password.count >= 6 && password.count <= 12 && !password.isEmpty
}
// 密码字母验证
static func validatePasswordLetter(_ password: String) -> Bool {
return password.containsLetter && !password.isEmpty
}
// 密码数字验证
static func validatePasswordNumber(_ password: String) -> Bool {
return password.containsNumber && !password.isEmpty
}
// 完整密码验证
static func validatePassword(_ password: String) -> Bool {
return validatePasswordLength(password) &&
validatePasswordLetter(password) &&
validatePasswordNumber(password)
}
}使用示例:
let email = "user@example.com"
let password = "password123"
let isValidEmail = Validate.validateEmail(email) // true
let isValidPassword = Validate.validatePassword(password) // true应用跳转工具
提供应用内外 URL 跳转功能。
enum OpenApp {
// 在外部浏览器打开 URL
static func openUrlOutsideApp(_ url: String) {
guard let url = URL(string: url) else { return }
UIApplication.shared.open(url)
}
// 在应用内打开 URL
static func openUrlInApp(_ url: String) {
guard let url = URL(string: url) else { return }
let safariViewController = SFSafariViewController(url: url)
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.windows.first?.rootViewController {
rootViewController.present(safariViewController, animated: true)
}
}
}使用示例:
// 在外部浏览器打开
OpenApp.openUrlOutsideApp("https://www.apple.com")
// 在应用内打开
OpenApp.openUrlInApp("https://developer.apple.com")兼容性功能
跨版本兼容
// iOS 17+ 兼容的 onChange 修饰符
someView.onChangeCompat(of: value) { oldValue, newValue in
// 处理值变化,自动适配 iOS 17+ 和早期版本
}
// 触觉反馈兼容
someView.sensoryFeedbackCompat(trigger: triggerValue)枚举定义
// 按钮样式类型
enum ButtonStyleType {
case common // 通用按钮样式
case text // 文本按钮样式
}
// 订阅类型
enum SubscriptionType: String, CaseIterable {
case revenueCat // RevenueCat 订阅
case storeKit2 // StoreKit2 订阅
}
// 展示样式
enum SheetOrFullScreenCover: String, CaseIterable {
case sheet // Sheet 展示
case fullScreenCover // 全屏覆盖
}依赖库
该模块需要以下外部库:
- JDStatusBarNotification - 状态栏通知
- WhatsNewKit - "新功能"展示
- AlertToast - Toast 通知
- RevenueCat (可选) - 订阅管理
- SafariServices - 应用内浏览器
最佳实践
1. 模块化使用
// 组合多个修饰符
ContentView()
.cardRoundedCorners()
.cardShadow()
.requirePremium()
.showToast($showToast, message: "成功!", isSuccess: true)2. 状态管理
@State private var isLoading = false
@State private var showError = false
Button("提交") {
isLoading = true
// 执行操作
}
.loading($isLoading)
.showToast($showError, message: "操作失败", isSuccess: false)3. 主题适配
// 自动适配深色/浅色模式
CardView()
.colorSchemeShadow(
light: .gray.opacity(0.3),
dark: .white.opacity(0.1)
)
.viewBackground()Last updated on