SwiftUI - 一步一步教你使用UIViewRepresentable封装网络加载视图(UIActivityIndicatorView)
概述
网络加载视图,在一个联网的APP上可以讲得上是必须要的组件,在SwiftUI中它并没有提供如 UIKit 中的UIActivityIndicatorView直接提供给我们调用,但是我们可以通过 SwiftUI 中的UIViewRepresentable协议封装UIActivityIndicatorView来使用它。
介绍 UIViewRepresentable
那么UIViewRepresentable到底有着什么样的作用呢?
它可以将 UIKit 封装成 SwiftUI View,这意味着我们可以通过它来搭建桥梁,可以很方便地复用以往在 UIKit 所有的组件,这很强大。
接下来介绍它的两个必须实现的协议。
/// 创建一个 UIView 的视图组件用于展示
func makeUIView(context: Self.Context) -> Self.UIViewType
/// 更新视图组件到最新的内容
func updateUIView(_ uiView: Self.UIViewType, context: Self.Context)
封装网络加载视图(UIActivityIndicatorView)
我们开始封装网络加载视图(UIActivityIndicatorView),创建一个实现了 UIViewRepresentable 协议的结构体。
struct GCIndicatorView: UIViewRepresentable {}
接下来的步骤均按照Xcode的提示进行,不做任何的简化操作,如果你们想要知道如何简化,可以评论或私信告诉我,我下期补这个内容。
Xcode 提示缺少内容,点击红色小框后点击 Fix 按钮,将会补全缺失代码。

struct GCIndicatorView: UIViewRepresentable {
typealias UIViewType = UIActivityIndicatorView
}
将视图类型改成我们所需要的 UIActivityIndicatorView ,这里定义好之后,makeUIView 和 updateUIView 方法定义都会返回此处定义的视图类型。接下来 Xcode 还会提示缺失代码,我们继续重复上一步。


在 makeUIView 方法体内创建 UIActivityIndicatorView 视图,它接受一个参数 UIActivityIndicatorView.Style,因此我们使用 let 定义一个 type 类型为 UIActivityIndicatorView.Style 的属性。
let style: UIActivityIndicatorView.Style
func makeUIView(context: UIViewRepresentableContext<GCIndicatorView>) -> UIActivityIndicatorView {
return UIActivityIndicatorView(style: style)
}
因为 Style 类型是定义在 UIActivityIndicatorView 里面的,所以在使用的时候提示是 UIActivityIndicatorView.Style,这样的好处是不会污染项目的命名空间,它只有两个类型可选。
public enum Style : Int {
@available(iOS 13.0, *)
case medium /// 尺寸是中等
@available(iOS 13.0, *)
case large // 尺寸是大的
}
我们再定义一个 color 属性,用于改变加载视图的颜色。在初始化视图时,为了可以选择忽略此属性,因此我们使用 var 定义为可变属性。
var color: UIColor? = nil
func makeUIView(context: UIViewRepresentableContext<GCIndicatorView>) -> UIActivityIndicatorView {
let activityIndicatorView = UIActivityIndicatorView(style: style)
activityIndicatorView.color = color
return activityIndicatorView
}
这里有一个小技巧,不知道你们发现了没有?我在定义 color 属性的时候,设定了它的默认值是 nil,这有什么好处呢?这里先看一下初始化时的代码提示。

它的作用就是可以让你在初始化视图时,有两个方法让你选择,明确地告诉你可以忽略有 color 或者没有 color 的定义。当然你不特定去设定默认值为 nil,你也可以在初始化时手动删除 color 字段,但我觉得按我这样的方法会更清晰一点,在调用的时侯。
我们在开始请求网络时显示加载视图,在网络请求后隐藏加载视图,为了实现这个操作,我们定义一个布尔类型的 isShowing 属性,同时还需使用 @Binding 修饰属性。
使用 @Binding 修饰的属性,属性会变成一个引用类型,从父视图传递给子视图,这样父子视图的状态就可以关联起来了,当属性变化时会同时改变父子视图。
在 UIViewRepresentable 里,它的改变会调起 updateUIView 方法,我们可以在此方法中更新视图。
func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<GCIndicatorView>) {
isShowing ? uiView.startAnimating() : uiView.stopAnimating()
}
小知识: UIActivityIndicatorView 组件需要调起 startAnimating 时才会显示视图,否则它是隐藏的
使用封装好的加载视图 GCIndicatorView
我们需要让加载视图显示在界面的正中间,因此使用 ZStack,它可以使在其内的组件叠加起来。同时需要定义一个布尔型的 isShowing 属性,并使用 @State 修饰它。使用 @State 修饰的属性,可以在其值发生变更时同时更新其关联的所有视图。
我们在界面上创建一个 ZStack,里面包含有一个按钮,点击按钮时将显示加载视图,在3秒后自动消失。通过条件语句判断 isShowing 为 true 时才显示视图,否则隐藏视图。
在某些情况下,在显示加载视图的时候不允许用户点击其它视图,需要等待网络请求完成后才能进行操作,因此需要给 ZStack 加上 disabled 方法,用于禁止操作事件。
struct GCHomeView: View {
@State var isShowing = false
var body: some View {
ZStack {
Button(action: {
self.isShowing = true
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.isShowing = false
}
}) {
Text("网络请求开始")
}
if isShowing {
GCIndicatorView(isShowing: $isShowing, style: .large)
}
}
.disabled(isShowing)
}
}
效果预览

Demo 源码下载
我已经把 Demo 上传至 GitHub 上面,有需要的朋友可以去下载运行一下,当然你也可以跟着文章去做一遍,这样更有利于你掌握此方面的知识。
文章篇幅有点长,虽然教的东西也挺简单,但概述得比较详细。任何东西都是先从简单入手的,才不会造成劝退不是吗?哈哈,此文章针对于新手而言还是很友好的,对于已经会的人来讲就可能废话有点多了,如果必须要喷,请轻喷,我比较玻璃心。
如果你觉得本文章对你有帮助,请关注我,你的关注就是我写文章的动力,下期会更精彩噢!
关于作者
博文作者:GarveyCalvin
微博:https://weibo.com/feiyueharia
博客园:https://www.cnblogs.com/GarveyCalvin
本文版权归作者,欢迎转载,但必须保留此段声明,并给出原文链接,谢谢合作!
公众号
作者第一次运营公众号,请你们一定要关注我的公众号,给我点动力,后期主要运营公众号为主。这是第一篇发布文章,需要你们的支持,谢谢你们!

QQ群
一起讨论 SwiftUI,群主喜欢看热闹,当吃瓜人员。进来时填写你在哪里看到此文章的,并介绍下自己,一句话就行。

SwiftUI - 一步一步教你使用UIViewRepresentable封装网络加载视图(UIActivityIndicatorView)的更多相关文章
- Android 框架练成 教你打造高效的图片加载框架(转)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多, ...
- Android 框架练成 教你打造高效的图片加载框架
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多, ...
- 一步一步重写 CodeIgniter 框架 (5) —— 实现Controller,并加载Model
CodeIgniter 框架采用MVC模式,而MVC模式中起纽带作用的就是C(控制器),在控制器的中通过加载模型获得数据,将数据传到视图中进行展示.本课将实现在控制器中加载模型. 1. 控制器的实现 ...
- 在Laravel中一步一步创建Packages
首先要看一下Laravel官方文档,这是最新4.2的文档,假设想看中文的话点击此处,基本一样.这个github上的库setup-laravel4-package,也是一步一步介绍怎样创建一个包.并关联 ...
- 一步一步教你如何在linux下配置apache+tomcat(转)
一步一步教你如何在linux下配置apache+tomcat 一.安装前准备. 1. 所有组件都安装到/usr/local/e789目录下 2. 解压缩命令:tar —vxzf 文件名(. ...
- 一步一步教你将普通的wifi路由器变为智能广告路由器
一步一步教你将普通的wifi路由器变为智能广告路由器 相信大家对WiFi智能广告路由器已经不再陌生了,现在很多公共WiFi上网,都需要登录并且验证,这也就是WiFi广告路由器的最重要的功能.大致就是下 ...
- 一步一步教你使用Git
一步一步教你使用Git 互联网给我们带来方便的同时,也时常让我们感到困惑.随便搜搜就出一大堆结果,然而总是有大量的重复和错误.小妖发出的内容,都是自己实测过的,有问题请留言. 现在,你已经安装了Git ...
- 使用WPF教你一步一步实现连连看
使用WPF教你一步一步实现连连看(一) 第一步: 问题,怎样动态的建立一个10*10的grid(布局) for (int i = 0; i < 10; i++){ RowDefinition r ...
- 一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app
一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app 转载 作者:jrainlau 链接:https://segmentfault.com/a/1190000005844155 ...
随机推荐
- python https请求报错:SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
python爬虫,使用requests库发送https请求报错:SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 解决方法: imp ...
- 洛谷1972 HH的项链 树状数组查询区间内不同的数的数量
题目链接:https://www.luogu.com.cn/problem/P1972 题意大致是:给定一个序列长度为n,给出m个查询区间,要求响应是区间内不同的数的个数.为此我们考虑到树状数组的区间 ...
- [dp]牛牛与数组
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit IO Format: %lld 题目描述 牛牛喜欢这样的数组: 1:长度为n 2:每一个 ...
- vnpy源码阅读学习(8):关于app
关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...
- List<Object>转List<T>
今天遇到一个麻烦,公司有个项目用了一个封装dao的模板,他妈的不管是查一条数据的方法,还是查一个集合数据的方法,全都返回Object或List<Object> 由于对象是Object根本不 ...
- adb的基本安装和介绍(一)
一,什么是adb? adb全称为Android Debug Bridge,就是起到调试桥的作用.顾名思义,adb就是android sdk 的一个工具 借助adb工具,我们可以管理设备或手机模拟器的状 ...
- Jmeter接口测试之参数化(十)
在接口测试中,某些时候一些场景会使用到参数化的场景,参数化简单的说就是同一个请求需要不同的数据,比如在性能测试中需要并发多个用户的场景,这样的目的是为了模拟真实的用户场景,需要模拟不同的账号,这里就需 ...
- 如何通过 JavaCSV 类库来优雅地(偷懒)读写 CSV 文件?
欢迎关注笔者的公众号: 小哈学Java, 专注于推送 Java 领域优质干货文章!! 个人博客: https://www.exception.site/essay/how-to-create-read ...
- Windows系统向Ubuntu传输文件
PuTTY传输: 安装PuTTY,然后将PuTTY安装目录下的pscp.exe文件拷贝到/Windows/System32/目录下,在cmd控制台执行命令: # pscp 要传输的文件路径 ubunt ...
- MATLAB 大数相乘溢出显示
解一道面试题——华为社招现场面试1:请使用代码计算1234567891011121314151617181920*2019181716151413121110987654321 . 乘积是逐位相乘,也 ...