8

SwiftUI - 一步一步教你使用UIViewRepresentable封装网络加载视图(UIActivityIndicat...

 3 years ago
source link: https://www.cnblogs.com/GarveyCalvin/p/representtable-uikit.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

网络加载视图,在一个联网的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 按钮,将会补全缺失代码。

007S8ZIlgy1gdy27inumdj310u04u75c.jpg

struct GCIndicatorView: UIViewRepresentable {
    typealias UIViewType = UIActivityIndicatorView
}

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

007S8ZIlgy1gdy27u9ozjj310u052wfw.jpg

007S8ZIlgy1gdy2h0rjopj30zm0cawhp.jpg

在 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,这有什么好处呢?这里先看一下初始化时的代码提示。

007S8ZIlgy1gdy284nbmzj3164038n0v.jpg

它的作用就是可以让你在初始化视图时,有两个方法让你选择,明确地告诉你可以忽略有 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)
    }
}
007S8ZIlgy1gdy28axtyrg309f0k0dhv.gif

Demo 源码下载

我已经把 Demo 上传至 GitHub 上面,有需要的朋友可以去下载运行一下,当然你也可以跟着文章去做一遍,这样更有利于你掌握此方面的知识。

文章篇幅有点长,虽然教的东西也挺简单,但概述得比较详细。任何东西都是先从简单入手的,才不会造成劝退不是吗?哈哈,此文章针对于新手而言还是很友好的,对于已经会的人来讲就可能废话有点多了,如果必须要喷,请轻喷,我比较玻璃心。

如果你觉得本文章对你有帮助,请关注我,你的关注就是我写文章的动力,下期会更精彩噢!

博文作者:GarveyCalvin

微博:https://weibo.com/feiyueharia

博客园:https://www.cnblogs.com/GarveyCalvin

本文版权归作者,欢迎转载,但必须保留此段声明,并给出原文链接,谢谢合作!

作者第一次运营公众号,请你们一定要关注我的公众号,给我点动力,后期主要运营公众号为主。这是第一篇发布文章,需要你们的支持,谢谢你们!

007S8ZIlgy1gdy28erjq7j305z05z0t2.jpg

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK