SwiftUI入门 - 17. 封装一个自己的View,View作为参数

置顶

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

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

继续

之前我们已经基本实现了接口的请求,本章我们来讨论如何封装一个自己的 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 是差不多的。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我码玄黄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值