SwiftUI进度指示器:遵循gh_mirrors/swi/swift-style-guide的优雅实现

【免费下载链接】swift-style-guide 【免费下载链接】swift-style-guide 项目地址: https://gitcode.com/gh_mirrors/swi/swift-style-guide

你是否曾在开发SwiftUI应用时,为进度指示器的代码风格不一致而困扰?是否想让加载状态展示既符合Apple设计规范,又保持代码的可读性和可维护性?本文将基于gh_mirrors/swi/swift-style-guide项目规范,从基础实现到高级定制,全面讲解如何构建符合专业标准的SwiftUI进度指示器。读完本文,你将掌握:规范的进度指示器代码写法、SwiftLint配置技巧、复杂场景下的状态管理,以及如何通过扩展实现可复用组件。

基础实现:符合规范的进度指示器

SwiftUI提供了两种原生进度指示器:ProgressView(环形进度)和线性进度指示器。根据代码组织规范,我们应使用扩展分离不同功能,保持主视图简洁。

import SwiftUI

struct ContentView: View {
  @State private var isLoading = false
  
  var body: some View {
    VStack(spacing: 20) {
      Button("加载数据") {
        isLoading.toggle()
        // 模拟网络请求
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
          isLoading = false
        }
      }
      .disabled(isLoading)
      
      if isLoading {
        ProgressView("加载中...")
          .progressViewStyle(CircularProgressViewStyle(tint: .blue))
      }
    }
  }
}

// MARK: - 线性进度指示器
extension ContentView {
  private var linearProgress: some View {
    ProgressView(value: 0.5)
      .progressViewStyle(LinearProgressViewStyle(tint: .green))
      .frame(height: 4)
  }
}

上述代码遵循了命名规范,使用camelCase命名属性和方法,通过// MARK: -分隔不同功能模块。值得注意的是,根据可选类型规范,我们使用@State private var isLoading = false而非可选类型,因为加载状态只有两种明确状态。

集成SwiftLint:确保代码风格一致性

为保证团队协作时的代码风格统一,gh_mirrors/swi/swift-style-guide推荐使用SwiftLint工具。根据SWIFTLINT.markdown文档,需将配置文件com.raywenderlich.swiftlint.yml放置在用户主目录,并在Xcode中配置运行脚本。

添加Run Script

在Xcode的Build Phases中添加如下脚本:

PATH=/opt/homebrew/bin:$PATH
if [ -f ~/com.raywenderlich.swiftlint.yml ]; then
  if which swiftlint >/dev/null; then
    swiftlint --no-cache --config ~/com.raywenderlich.swiftlint.yml
  fi
fi

此配置会在每次构建时自动检查代码风格,例如强制移除行尾空格(需在Xcode偏好设置中开启对应选项):

Xcode行尾空格设置

高级定制:符合规范的自定义进度指示器

当原生组件无法满足需求时,我们需要创建自定义进度指示器。根据类与结构体规范,应优先使用结构体(值类型)实现UI组件。

// MARK: - 自定义进度指示器
struct CustomProgressView: View {
  let progress: Double
  let tintColor: Color
  
  var body: some View {
    ZStack {
      Circle()
        .stroke(Color(.systemGray5), lineWidth: 8)
      Circle()
        .trim(from: 0, to: progress)
        .stroke(tintColor, style: StrokeStyle(lineWidth: 8, lineCap: .round))
        .rotationEffect(.degrees(-90))
        .animation(.easeInOut, value: progress)
    }
    .frame(width: 40, height: 40)
  }
}

// MARK: - 预览
struct CustomProgressView_Previews: PreviewProvider {
  static var previews: some View {
    CustomProgressView(progress: 0.7, tintColor: .blue)
  }
}

上述代码遵循了访问控制规范,未使用默认的internal修饰符,同时通过扩展组织代码,将预览代码分离到单独扩展中。特别注意,根据静态方法规范,我们避免使用静态属性存储颜色等常量,而是通过参数传递实现定制化。

复杂场景:进度状态管理与错误处理

在实际项目中,进度指示器通常与网络请求等异步操作关联。根据黄金路径原则,应优先处理成功路径,使用guard语句提前退出异常情况。

class DownloadManager: ObservableObject {
  @Published var progress: Double = 0
  @Published var isDownloading = false
  @Published var error: Error?
  
  func downloadFile() {
    guard !isDownloading else { return }
    
    isDownloading = true
    progress = 0
    
    // 模拟下载进度
    let totalSteps = 100
    for step in 1...totalSteps {
      DispatchQueue.main.asyncAfter(deadline: .now() + Double(step) * 0.05) { [weak self] in
        guard let self = self else { return }
        
        self.progress = Double(step) / Double(totalSteps)
        
        if step == totalSteps {
          self.isDownloading = false
        }
      }
    }
  }
}

在视图中使用时,遵循可选绑定规范,使用if let安全解包错误信息:

struct DownloadView: View {
  @StateObject private var manager = DownloadManager()
  
  var body: some View {
    VStack(spacing: 20) {
      if manager.isDownloading {
        CustomProgressView(progress: manager.progress, tintColor: .green)
        Text("已完成: \(Int(manager.progress * 100))%")
      } else {
        Button("开始下载") {
          manager.downloadFile()
        }
      }
      
      if let error = manager.error {
        Text("错误: \(error.localizedDescription)")
          .foregroundColor(.red)
      }
    }
  }
}

最佳实践与SwiftLint规则例外

尽管SwiftLint帮助我们保持代码风格一致,但在某些场景下需要临时禁用规则。例如,在SwiftUI中使用多尾随闭包语法时:

// swiftlint:disable multiple_closures_with_trailing_closure
Button(action: {
  manager.downloadFile()
}) {
  Image(systemName: "arrow.down")
    .padding()
    .background(Circle().fill(Color.blue))
    .foregroundColor(.white)
}
// swiftlint:enable multiple_closures_with_trailing_closure

根据SwiftLint策略,这种情况是允许的例外。记得在禁用规则后重新启用,避免影响后续代码检查。

总结与扩展阅读

本文介绍了如何遵循gh_mirrors/swi/swift-style-guide规范实现SwiftUI进度指示器,包括基础用法、自定义组件、状态管理和SwiftLint配置。关键要点:

  1. 使用扩展分离不同功能模块,保持代码组织清晰
  2. 优先使用结构体实现UI组件,遵循值类型优先原则
  3. 通过SwiftLint确保代码风格一致性,合理处理规则例外
  4. 遵循黄金路径原则,使用guard语句提前处理异常情况

更多Swift编码规范细节,可参考:

希望本文能帮助你写出既美观又规范的SwiftUI代码。如果你有更好的实现方案或对规范有疑问,欢迎通过项目贡献指南参与讨论。

贡献指南 | 项目许可证 | 贡献者名单

【免费下载链接】swift-style-guide 【免费下载链接】swift-style-guide 项目地址: https://gitcode.com/gh_mirrors/swi/swift-style-guide

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐