SwiftUI目前还在发展阶段,有些视图还未能提供。但是苹果给我们提供复用机制,很容易将历史代码移植到SwiftUI世界中。下面我们通过UIViewRepresentable将UIKit的UIActivityIndicator封装一下
最终效果
实现步骤
首先,我们将UIActivityIndicator包装到一个ActivityIndicator视图中,该视图可用作SwiftUI视图。其中 isAnimating作为动画的开关
struct ActivityIndicator: UIViewRepresentable {
@Binding var isAnimating: Bool
let style: UIActivityIndicatorView.Style
func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView {
return UIActivityIndicatorView(style: style)
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) {
isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
}
}
在实际开发中,我们很少单独使用UIActivityIndicator,因为实在太单调了。我通常是添加UILabel来告知用户我们正在处理的事项,例如:加载,计算,载入等,在SwiftUI世界里我们用Text就可以很好的完成这个任务。
由于我们现在将ActivityIndicator作为SwiftUI视图,因此我们可以轻松地利用SwiftUI强大组合功能,联合其他View来创建功能强大的HUD(Head up Display))提示框。
另外,为此了示范loading页面的显示与隐藏,我们还增加了隐藏和显示按钮。
显示按钮代码
Button(action:{
self.isShowing = !self.isShowing
//self.isAnimating = false
}){
Text(" Show loading ").foregroundColor(.white)
}.background(Color.orange)
.cornerRadius(2.0)
.shadow(radius: 2)
隐藏按钮效果
隐藏按钮代码
Button(action:{
self.isShowing = false
//self.isAnimating = false
}){
Text(" Hide ")
}.background(Color.white)
.cornerRadius(2.0)
.shadow(radius: 2)
组装
struct LoadingView: View where Content: View {
@Binding var isShowing: Bool
@State var isAnimating: Bool = true
var content: () -> Content
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.content()
.disabled(self.isShowing)
.blur(radius: self.isShowing ? 3 : 0)
VStack {
Text("Loading...")
ActivityIndicator(isAnimating: self.$isAnimating, style: .large)
Button(action:{
self.isShowing = false
//self.isAnimating = false
}){
Text(" Hide ")
}.background(Color.white)
.cornerRadius(2.0)
.shadow(radius: 2)
}
.frame(width: geometry.size.width / 2,
height: geometry.size.height / 5)
.background(Color.secondary.colorInvert())
.foregroundColor(Color.primary)
.cornerRadius(20)
.opacity(self.isShowing ? 1 : 0)
}
}
}
}
主页面
struct ContentView: View {
@State var isShowing: Bool = true
var body: some View {
LoadingView(isShowing:self.$isShowing) {
VStack{
Button(action:{
self.isShowing = !self.isShowing
//self.isAnimating = false
}){
Text(" Show loading ").foregroundColor(.white)
}.background(Color.orange)
.cornerRadius(2.0)
.shadow(radius: 2)
NavigationView {
List(["1", "2", "3", "4", "5"], id: \.self) { row in
Text(row)
}.navigationBarTitle(Text("A List"), displayMode: .large)
}
}
}
}
}
项目完整代码
import SwiftUI
struct ActivityIndicator: UIViewRepresentable {
@Binding var isAnimating: Bool
let style: UIActivityIndicatorView.Style
func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView {
return UIActivityIndicatorView(style: style)
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) {
isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
}
}
struct LoadingView: View where Content: View {
@Binding var isShowing: Bool
@State var isAnimating: Bool = true
var content: () -> Content
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.content()
.disabled(self.isShowing)
.blur(radius: self.isShowing ? 3 : 0)
VStack {
Text("Loading...")
ActivityIndicator(isAnimating: self.$isAnimating, style: .large)
Button(action:{
self.isShowing = false
//self.isAnimating = false
}){
Text(" Hide ")
}.background(Color.white)
.cornerRadius(2.0)
.shadow(radius: 2)
}
.frame(width: geometry.size.width / 2,
height: geometry.size.height / 5)
.background(Color.secondary.colorInvert())
.foregroundColor(Color.primary)
.cornerRadius(20)
.opacity(self.isShowing ? 1 : 0)
}
}
}
}
struct ContentView: View {
@State var isShowing: Bool = true
var body: some View {
LoadingView(isShowing:self.$isShowing) {
VStack{
Button(action:{
self.isShowing = !self.isShowing
//self.isAnimating = false
}){
Text(" Show loading ").foregroundColor(.white)
}.background(Color.orange)
.cornerRadius(2.0)
.shadow(radius: 2)
NavigationView {
List(["1", "2", "3", "4", "5"], id: \.self) { row in
Text(row)
}.navigationBarTitle(Text("A List"), displayMode: .large)
}
}
}
}
}
参考资料
https://peacemoon.de/blog/2019/06/10/activity-indicator-with-swiftui/
更多SwiftUI教程和代码关注专栏
QQ:3365059189
SwiftUI技术交流QQ群:518696470
- 请关注我的专栏icloudend, SwiftUI教程与源码
https://www.jianshu.com/c/7b3e3b671970