译自https://www.hackingwithswift.com/books/ios-swiftui/bookworm-introduction更多内容,欢迎关注公众号 「Swift花园」喜欢文章?不如来个 ➕三连?关注专栏,关注我
Bookworm:介绍
在这个项目中我们要构建一个应用,用于跟踪你读过的书和你对它们的看法,延续 Cupcake Corner 项目的做法:让我们用上你已经掌握的技能,并且增加一些额外奖励的新技能,让你的技能熟练度再上一个台阶。
这一回你将认识 Core Data,它是 Apple 的一个久经战阵的框架,用于处理数据框。这个项目将扮演 Core Data 介绍者的角色,稍后我们会介绍更多细节。
与此同时,我们还将构建我们的第一个自定义组件 —— 一个评价等级的星星 widget,用户可以点击它来为每本书评分。这也意味着,我们将引入一个新的属性包装器,它叫@Binding
。
如往常一样,我们先速览一遍你将在这个项目中用到的新技术。首先,请创建一个新的 iOS 应用,取名叫 Bookworm,使用 Single View App 项目模板。
译自https://www.hackingwithswift.com/books/ios-swiftui/creating-a-custom-component-with-binding
用 Binding 创建自定义组件
你已经了解 SwiftUI 的@State
属性包装器如何同本地值类型协同工作,以及@ObservedObject
如何同共享的引用类型协同工作。其实还有第三个选项,叫@Binding
, 它能让我们将一个视图的@State
属性连接到底层的模型数据。
想想看:当我们创建一个 toggle 开关时,我们像下面这样发送某个可以被改变的布尔属性:
@StateprivatevarrememberMe=falsevarbody:someView{Toggle(isOn:$rememberMe){Text("Remember Me")}}
因此,Toggle
需要在用户和它交互时改变我们的布尔值,但它是如何记住自己应该改变成哪个值呢?
这正是@Binding
发挥作用的地方:它让我们创建一个在视图中可修改的值,这个值实际指向其他地方的某个值。对于Toggle
t,开关改变自身对于一个布尔型的本地绑定,而幕后实际上维护一个视图中的@State
属性。
这使得@Binding
对于任何自定义 UI 组件都至关重要,其中的关键在于 UI 组件就像其他东西一样,只是 SwiftUI 视图,但@Binding
使得它们被区分开:它们既可以有本地的@State
属性,同时也暴露@Binding
属性,以便自己可以和其他视图连接。
为了说明这一点,我们将创建一种新的按钮:这种按钮在按下时保持被按下的视觉效果。基本的实现方式和你之前见到过的一样:一个带填充的按钮,线性渐变的背景,Capsule
的裁切形状,等等 —— 把下面的代码添加到 ContentView.swift :
structPushButton:View{lettitle:String@StatevarisOn:BoolvaronColors=[Color.red,Color.yellow]varoffColors=[Color(white:0.6),Color(white:0.4)]varbody:someView{Button(title){self.isOn.toggle()}.padding().background(LinearGradient(gradient:Gradient(colors:isOn?onColors:offColors),startPoint:.top,endPoint:.bottom)).foregroundColor(.white).clipShape(Capsule()).shadow(radius:isOn?0:5)}}
这里我用了属性来控制渐变色,以便我们可以定制按钮的背景。
我们现在可以在主界面中使用刚才创建的按钮,像这样:
structContentView:View{@StateprivatevarrememberMe=falsevarbody:someView{VStack{PushButton(title:"Remember Me",isOn:rememberMe)Text(rememberMe?"On":"Off")}}}
按钮下方有一个文本视图,以便我们追踪按钮状态 —— 尝试运行代码,观察按钮的工作方式。
你将发现,点击按钮确实会影响它的呈现效果,但我们的文本视图并不会反映这个变化 —— 它一直都是 Off。显然,在按钮点击时有改变发生了,因为按钮的外观发生了变化,但这个变化并没有在ContentView
中体现。
这里的情况是我们实际上定义了一种单向的数据流:ContentView
拥有rememberMe
布尔属性,并且被用于创建PushButton
—— 这个按钮有一个由ContentView
. 提供的初始值。但是,一旦按钮创建,它就接管了那个值:它在按钮内部触发isOn
属性在true
或者false
间变化,但并不会把变化传回ContentView
。
这是一个问题,因为这样一来我们就有两个 sources of truth:ContentView
存储一个值,而PushButton
存储另一个。幸运的是,借助@Binding
:我们可以在PushButton
和任何使用它的东西之间建立双向的连接,以便一边改变,另一边也同步。
为了切换到@Binding
,我们只需要做两处改动。首先,在PushButton
里,把它的isOn
属性改成这样:
@BindingvarisOn:Bool
其次,在ContentView
里,修改我们创建按钮的方式,变成下面这样:
PushButton(title:"Remember Me",isOn:$rememberMe)
我们在rememberMe
之前加了一个$
符号 —— 代表我们传入的是绑定,而不是布尔类型。
我的公众号这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容