• SwiftUI


    概述

    网络加载视图,在一个联网的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,群主喜欢看热闹,当吃瓜人员。进来时填写你在哪里看到此文章的,并介绍下自己,一句话就行。

  • 相关阅读:
    Linux之开源软件移植
    数学问题的解题方法(模板)
    图论相关算法理解和总结
    关于ACM,关于CSU
    hdu 4607(树的直径)
    树的直径
    SGU-181 X-Sequence
    1629 B君的圆锥
    1134 最长递增子序列(暴力写的)
    1483 化学变换(暴力)
  • 原文地址:https://www.cnblogs.com/GarveyCalvin/p/representtable-uikit.html
Copyright © 2020-2023  润新知