打通SwiftUI任督二脉

金歌  金牌会员 | 2024-5-12 16:12:03 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 843|帖子 843|积分 2529


序言

开年的第一篇文章,本日分享的是SwiftUI,SwiftUI出来好几年,之前一直没学习,所以现在才开始;如果各人还留在 iOS 开发,这们语言也是一个趋势; 现在待业中....   不得不说已逝的2023年,各人开始都抱着一解封,经济都会向上转好,但是实际不是我们想象那样;现在我也在学习 SwiftUI,而且努力找工作中....;至于 2024 年经济怎样,咱们作为老百姓在大情况和环球经济影响下;坦然面对,提拔本身。 这里不得不说国人坚韧不拔的精神。“卷”  -- 努力吧Coding人
SwiftUI体验

Xcode创建项目之后出现工程默认创建的UI界面;如下

一开始心里对本身说:"SwiftUI作为iOS开发新的UI体系,为啥初创的项目这么多代码,给初学者看到,一种压迫感,心想这语法好复杂,不想学了";不管你是不是如许心里,我刚开始瞥见,这么一坨代码,没什么心思,于是索性删掉;按本身能理解学习的方式来操作;于是做了简化:
  1. import SwiftUI
  2. import SwiftData
  3. struct ContentView: View {
  4.    
  5.     var body: some View {
  6.         Text("hello,word")
  7.     }
  8. }
  9. #Preview {
  10.     ContentView()
  11.         .modelContainer(for: Item.self, inMemory: true)
  12. }
复制代码
关键字 some

关键字some啥玩意儿,完全陌生;先看看View;点击进入源码布局检察:
  1. @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
  2. public protocol View {
  3.     /// The type of view representing the body of this view.
  4.     ///
  5.     /// When you create a custom view, Swift infers this type from your
  6.     /// implementation of the required ``View/body-swift.property`` property.
  7.     associatedtype Body : View
  8.     @ViewBuilder @MainActor var body: Self.Body { get }
  9. }
复制代码
一堆英文注解估计各人不喜欢看,我就没贴出来了;简单来说:
View 是一个泛型协议,它定义了全部视图类型需要遵照的接口,通过some修饰;表示 "我返回一个满足View 协议的某种类型"。some关键字告诉 Swift,虽然我们知道body必须返回一个View,但我们不确定具体是哪种 View(比方,Text, Image, VStack 等)。
协议里有一个associatedtype,body,其实这种协议就是当作束缚情势使用;只要服从这种协议编译器每次闭包中返回的一定是一个确定,服从View协议的类型。
那么苹果工程师使用Swift5.1 Opaque return types特性,开发者提供了一个灵活的开发模式,抹掉了具体的类型,不需要修改公共API来确定每次闭包的返回类型,也降低了代码书写难度。(学学苹果那些大神思想,不错)
在来看看Preview
  1. struct ContentView_Previews:PreviewProvider{
  2.     static var previews: some View{
  3.         ContentView()
  4.         
  5.     }
  6. }
复制代码
PreviewProvider就一个协议类,它的额作用提供swiftUI不用运行,就能直接看到UI渲染变化,我以为这个挺好,减少开发人员对UI运行测试次数和时间,而previews就是一个静态属性,返回一个 View 对象,用于在预览面板中展示。
@State属性包装器

@State属性包装器解决UI界面上,数据同步以及实时刷新的功能。一般来说数据更新完,界面 UI 同时更新。在 SwiftUI里面,视图中声明的任何状态、内容和布局,源头一旦发生改变,会自动更新视图,因此,只需要一次布局,这个时候出现了@State,它来解决与UI之间数据状态问题。
它的概念就是:@State 是一个属性包装器(property wrapper),用于声明状态属性(state property)
当状态属性发生变化时,SwiftUI 会自动更新视图以反映最新的状态。
属性的值被存储在特殊的内存区域中,这个区域与 View struct 是隔离的 至于被它修饰的属性内存存储与分布现在无从得知,还没学习到那么深入,这事儿慢慢来,不是一天两天的,先上个代码看看它怎么使用的:
  1. import SwiftUI
  2. struct StateBootcamp: View {
  3.    
  4.     @State var bgkColor:Color = Color.blue
  5.     @State var cut:Int = 0
  6.    
  7.     var body: some View {
  8.         
  9.         ZStack{
  10.             
  11.             bgkColor
  12.                 .ignoresSafeArea(.all)
  13.             
  14.             VStack(spacing: 20){
  15.                
  16.                 Text("Hello, World!")
  17.                     .font(.title)
  18.                
  19.                 Text("count:\(cut)")
  20.                     .font(.largeTitle)
  21.                
  22.                 HStack(spacing: 20){
  23.                     Button("Button01") {
  24.                         cut+=1
  25.                         bgkColor = Color.red
  26.                     }
  27.                     .font(.title)
  28.                     .foregroundColor(.white)
  29.                     
  30.                     Button("Button02") {
  31.                         cut-=1
  32.                         bgkColor = .purple
  33.                     }
  34.                     .font(.title)
  35.                     .foregroundColor(.white)
  36.                 }
  37.                 Button("默认"){
  38.                     cut=0
  39.                     bgkColor = .blue
  40.                 }
  41.                 .font(.title)
  42.                 .foregroundColor(.white)
  43.             }
  44.         }
  45.     }
  46. }
  47. #Preview {
  48.     StateBootcamp()
  49. }
复制代码
其实一看代码,就一幕了然,知道它的使用与作用;如果你写过swift代码,这些东西很好理解,但是只会OC,那么我建议你学习下swift;在来看swiftUI语法糖才更好理解。
在看看源码:
  1. @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
  2. @frozen @propertyWrapper public struct State<Value> : DynamicProperty {
  3.     public init(wrappedValue value: Value)
  4.     public init(initialValue value: Value)
  5.     public var wrappedValue: Value { get nonmutating set }
  6.     public var projectedValue: Binding<Value> { get }
  7. }
  8. @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
  9. extension State where Value : ExpressibleByNilLiteral {
  10.     /// Creates a state property without an initial value.
  11.     ///
  12.     /// This initializer behaves like the ``init(wrappedValue:)`` initializer
  13.     /// with an input of `nil`. See that initializer for more information.
  14.     @inlinable public init()
  15. }
复制代码
可以看到State是一个布局体,由@propertyWrapper包装的。@propertyWrapper是属性包装器。property wrapper 做的事情大体如下:
  1. -   为底层的存储变量`State<Int>`自动提供一组 **getter** 和 **setter** 方法,结构体内保存了`Int`的具体数值;
  2. -   在 body 首次求值前,将`State<Int>`关联到当前`View`上,为它在堆中对应当前`View`分配一个存储位置。
  3. -   为`@State`修饰的变量设置观察,当值改变时,触发新一次的`body`求值,并刷新 UI。
复制代码
SwiftUI底子组件

Spacer垫片:先贴贴代码
  1. import SwiftUI
  2. struct SpacerBootcampDemo: View {
  3.     var body: some View {
  4.         Text("Spacer UP")
  5.             .font(.largeTitle)
  6.         
  7.         Spacer()
  8.             .frame(width: 37)
  9.             .background(.blue)
  10.         
  11.         Text("Spacer Down")
  12.             .font(.largeTitle)
  13.         
  14.     }
  15. }
  16. #Preview {
  17.     SpacerBootcampDemo()
  18. }
复制代码
在看看效果图:

总结:Spacer 是一个灵活的空间视图,它的主要作用是在布局中自动调整自身的高度和宽度,以填满特定的空间;简单来说,它就是一个垫片,调整自身视图的高度,如果它附近有其他视图,也会受到Spacer影响。
ScrollView 如果你之前使用UIkit框架开发,在用SwiftUI,一下有点不适应,代码和之前的 UIkit 开发模式不太一样,但是大大缩短UI编写时间;先上代码:
[code]import SwiftUIstruct ScollViewBootcamp: View {        var body: some View {                ScrollView{            LazyVStack{                ForEach(0..

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表