美文网首页
SwiftUI入门 - 17. 封装一个自己的View,View

SwiftUI入门 - 17. 封装一个自己的View,View

作者: 思跃喵 | 来源:发表于2022-12-09 17:48 被阅读0次

    置顶

    菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行

    “不积跬步,无以至千里;不积小流,无以成江海”

    继续

    之前我们已经基本实现了接口的请求,本章我们来讨论如何封装一个自己的 View

    通过观察我们可以发现,我们自己封装的 View 都是在以行的方式调用,与原始的 View 调用比较不一样

    如图:

    很多的 View 都是可以写内容,和指定某个参数是一个 View 的,那么我们是否也可以封装一个这样的View 呢?如图:

    中间那个是我们传入的参数,头部和底部都是外面传入的,整个布局就已经是这样上中下三栏式了

    希望不用每次这样布局的时候都写一大堆,直接调用,传入参数和顶部底部的东西即可。

    这就很类似 vue 中的 默认插槽(default slot) 和 命名插槽。

    我们可以定义好布局、动画、样式等,再内容插入的地方,这样再调用起来就方便多了。

    思考 + 踩坑

    想到这个问题的时候第一反应自然是看看原生的view是怎么实现的。

    command+ 鼠标点击View -> Jump to Definition

    可以看到如下代码(省略了注释)

    @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
    public protocol View {
        associatedtype Body : View
        @ViewBuilder @MainActor var body: Self.Body { get }
    }
    

    这是一个 Protocol,先暂时理解为其他语言中的 Interface,即只能定义规范,不能定义实现

    我们可以看到 View 里面定义了一个 @ViewBuilder 的参数,其他的先不管😂

    同理,我们可以另起一个 View 进行尝试

    果然得到了报错。。。

    看报错的意思,这个 View 是个 Protocol ,所以要在前面加 any

    直接点一手 Fix

    又得到了新的报错:


    大意为:any View 不能放到 View 里面。

    实现

    到了这个报错的地步就很明了了,既然不能是个 any View,那就得是个实际的 View ,提前定义即可了。

    但是很显然,我们不能定义一个新的 bottom:Viewstruct 出来,因为我们要传的就是这个 View ,如果提前定义好了,我们传什么?所以就引出了以下的写法:

    // ExampleView.swift
    import SwiftUI;
    // <> 里面相当于我提前定义了一个View,但它还没有实现,以后用的
    struct ExampleView<Top:View,Bottom:View>:View{
        @State public var title:String;
        // 这个 bottom 方法是个 ViewBuilder,返回的是一个 Bottom
        @ViewBuilder public var bottom:()-> Bottom;
        // 这个 top 方法也是个 ViewBuilder,返回的是一个 Top
        @ViewBuilder public var top:() -> Top;
        var body: some View{
            top();
            Spacer();
            Text(title);
            Spacer();
            bottom();
        }
    }
    

    这次没有报错,于是我们就可以愉快地对这个 View 进行调用了

    //  helloworldApp.swift
    import SwiftUI
    @main
    struct helloworldApp: App {
        var body: some Scene {
            WindowGroup {
                // 允许调用Toast,来自扩展
                // IndexView()
                //  .enableToast()
                // 直接跟在后面用花括号包裹的
                // 默认是定义的里面的@ViewBuilder的第一个,本例中是 bottom
                // 其他的都必须使用命名参数
                ExampleView(title: "测试一个自己的View"){
                    Text("")
                } top: {
                    Text("top content")
                }
            }
        }
    }
    

    运行得到开头那张图的结果。

    总结

    1. 看到报错或者警告的时候别忘了点开那个红点,说不定有 Fix,看看官方建议怎么做,虽然有时候也不一定对😂
    2. 本文只是简单地展示了一下 View 封装的方式,这样我就可以写一些布局甚至页面的模板出来复用了。
    3. 官方原本的 Protocol 也是很好的例子,别忘了默认的一些视图和方法也是可以点开的,看看原本是怎么定义的。
    4. Protocol 后面再讨论具体的意义和使用,不过想来和其他语言中的 Interface 是差不多的。

    欢迎关注公主号【思跃喵】,一起探讨。

    相关文章

      网友评论

          本文标题:SwiftUI入门 - 17. 封装一个自己的View,View

          本文链接:https://www.haomeiwen.com/subject/nfeafdtx.html