SwiftUI从入门到精华

序文

开年的第一篇文章,今天共享的是SwiftUI,SwiftUI出来好几年,之前一向没学习,所以现在才开端;假如我们还留在 iOS 开发,这们言语也是一个趋势; 现在失业中…. 不得不说已逝的2023年,我们开端都抱着一解封,经济都会向上转好,可是现实不是我们幻想那样;现在我也在学习SwiftUI,并且尽力找工作中….;至于 2024 年经济怎样,我们作为老百姓在大环境和全球经济影响下;安然面对,提升自己。 这里不得不说国人坚定不移的精力。“卷”尽力吧Coding人

SwiftUI体会

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

SwiftUI从入门到精华

一开端心里对自己说:"SwiftUI作为iOS开发新的UI系统,为啥初创的项目这么多代码,给初学者看到,一种压迫感,心想这语法好杂乱,不想学了";不管你是不是这样心里,我刚开端看见,这么一坨代码,没什么心思,所以索性删掉;按自己能了解学习的方式来操作;所以做了简化:

import SwiftUI
import SwiftData
struct ContentView: View {
    var body: some View {
        Text("hello,word")
    }
}
#Preview {
    ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

要害some

要害字some啥玩意儿,完全生疏;先看看View;点击进入源码结构检查:

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {
    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required ``View/body-swift.property`` property.
    associatedtype Body : View
    @ViewBuilder @MainActor var body: Self.Body { get }
}

一堆英文注解估量我们不喜欢看,我就没贴出来了;简略来说: View是一个泛型协议,它定义了所有视图类型需求遵从的接口,通过some润饰;表明 “我回来一个满足View协议的某种类型”。some要害字告诉 Swift,尽管我们知道body有必要回来一个View,但我们不确认详细是哪种View(例如,Text,Image,VStack 等)。

协议里有一个associatedtypebody,其实这种协议便是当作约束形式运用;只需恪守这种协议编译器每次闭包中回来的一定是一个确认,恪守View协议的类型。

那么苹果工程师运用Swift5.1 Opaque return types特性,开发者供给了一个灵敏的开发形式,抹掉了详细的类型,不需求修改公共API来确认每次闭包的回来类型,也降低了代码书写难度。(学学苹果那些大神思维,不错)

在来看看Preview

struct ContentView_Previews:PreviewProvider{
    static var previews: some View{
        ContentView()
    }
}

PreviewProvider就一个协议类,它的额作用供给swiftUI不必运转,就能直接看到UI烘托变化,我觉得这个挺好,减少开发人员对UI运转测试次数和时间,而previews便是一个静态特点,回来一个View对象,用于在预览面板中展现。

@State特点包装器

@State特点包装器处理UI界面上,数据同步以及及时改写的功用。一般来说数据更新完,界面 UI 同时更新。在SwiftUI里面,视图中声明的任何状况、内容和布局,源头一旦产生改动,会自动更新视图,因此,只需求一次布局,这个时候呈现了@State,它来处理与UI之间数据状况问题。

它的概念便是:@State是一个特点包装器(property wrapper),用于声明状况特点(state property) 当状况特点产生变化时,SwiftUI 会自动更新视图以反映最新的状况。

特点的值被存储在特别的内存区域中,这个区域与 View struct 是隔离的 至于被它润饰的特点内存存储与分布现在无从得知,还没学习到那么深化,这事儿慢慢来,不是一天两天的,先上个代码看看它怎样运用的:

import SwiftUI
struct StateBootcamp: View {
    @State var bgkColor:Color = Color.blue
    @State var cut:Int = 0
    var body: some View {
        ZStack{
            bgkColor
                .ignoresSafeArea(.all)
            VStack(spacing: 20){
                Text("Hello, World!")
                    .font(.title)
                Text("count:(cut)")
                    .font(.largeTitle)
                HStack(spacing: 20){
                    Button("Button01") {
                        cut+=1
                        bgkColor = Color.red
                    }
                    .font(.title)
                    .foregroundColor(.white)
                    Button("Button02") {
                        cut-=1
                        bgkColor = .purple
                    }
                    .font(.title)
                    .foregroundColor(.white)
                }
                Button("默认"){
                    cut=0
                    bgkColor = .blue
                }
                .font(.title)
                .foregroundColor(.white)
            }
        }
    }
}
#Preview {
    StateBootcamp()
}

其实一看代码,就一幕了然,知道它的运用与作用;假如你写过swift代码,这些东西很好了解,可是只会OC,那么我建议你学习下swift;在来看swiftUI语法糖才更好了解。

在看看源码:

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct State<Value> : DynamicProperty {
    public init(wrappedValue value: Value)
    public init(initialValue value: Value)
    public var wrappedValue: Value { get nonmutating set }
    public var projectedValue: Binding<Value> { get }
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension State where Value : ExpressibleByNilLiteral {
    /// Creates a state property without an initial value.
    ///
    /// This initializer behaves like the ``init(wrappedValue:)`` initializer
    /// with an input of `nil`. See that initializer for more information.
    @inlinable public init()
}

能够看到State是一个结构体,由@propertyWrapper包装的。@propertyWrapper是特点包装器。property wrapper做的事情大体如下:

-   为底层的存储变量`State<Int>`自动供给一组 **getter****setter** 方法,结构体内保存了`Int`的详细数值;
-   在 body 首次求值前,将`State<Int>`相关到当时`View`上,为它在堆中对应当时`View`分配一个存储位置。
-`@State`润饰的变量设置调查,当值改动时,触发新一次的`body`求值,并改写 UI。

SwiftUI基础组件

Spacer垫片:先贴贴代码

import SwiftUI
struct SpacerBootcampDemo: View {
    var body: some View {
        Text("Spacer UP")
            .font(.largeTitle)
        Spacer()
            .frame(width: 37)
            .background(.blue)
        Text("Spacer Down")
            .font(.largeTitle)
    }
}
#Preview {
    SpacerBootcampDemo()
}

在看看作用图:

SwiftUI从入门到精华

总结:Spacer 是一个灵敏的空间视图,它的首要作用是在布局中自动调整本身的高度和宽度,以填满特定的空间;简略来说,它便是一个垫片,调整本身视图的高度,假如它周围有其他视图,也会遭到Spacer影响。

ScrollView 假如你之前运用UIkit结构开发,在用SwiftUI,一下有点不适应,代码和之前的 UIkit 开发形式不太相同,可是大大缩短UI编写时间;先上代码:


import SwiftUI
struct ScollViewBootcamp: View {
    var body: some View {
        ScrollView{
            LazyVStack{
                ForEach(0..<20){
                    (idx) in
                    VStack {
                        Text("Hello, World!")
                            .font(.title)
                            .foregroundStyle(.white)
                            .frame(width: UIScreen.main.bounds.width-20,height: 350)
                            .background(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<215)/255.0, green: CGFloat.random(in: 0..<235)/255.0, blue: CGFloat.random(in: 0...247)/255.0, alpha: 0.9)))
                            .clipShape(RoundedRectangle(cornerRadius: 10))
                        Rectangle()
                            .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0...187)/255.0, green: CGFloat.random(in: 0..<210)/255.0, blue: CGFloat.random(in: 0...237)/255.0, alpha: 0.9)))
                            .frame(width: UIScreen.main.bounds.width-20,height: 530)
                            .clipShape(RoundedRectangle(cornerRadius: 10))
                        ScrollView(.horizontal,showsIndicators: false,content: {
                            LazyHStack{
                                ForEach(0..<10){
                                    idx in
                                    Rectangle()
                                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0...167)/255.0, green: CGFloat.random(in: 0...131)/255.0, blue: CGFloat.random(in: 0...89)/255.0, alpha: 0.9)))
                                        .frame(width: 200, height: 300)
                                        .clipShape(RoundedRectangle(cornerRadius: 10))
                                }
                            }
                        })
                        .padding(.leading,10)
                        .padding(.trailing,10)
                    }
                }
            }
            .frame(width:UIScreen.main.bounds.width)
        }
    }
}
#Preview {
    ScollViewBootcamp()
}

上图看看作用:

SwiftUI从入门到精华

简略几句就能完成**ScrollView**的滑动作用;十分方便。

LazyVGrid 网格布局,先上代码:

import SwiftUI
struct GridViewBootcamp: View {
    let columns=[        GridItem(.flexible(),spacing: 6   ,alignment: .center),        GridItem(.flexible(),spacing: 6    ,alignment: .center),        GridItem(.flexible(),spacing: 6  ,alignment: .center),    ]
    var body: some View {
        ScrollView{
            LazyVGrid(columns: columns,
                      alignment: .center,
                      spacing: 6,
                      pinnedViews: [.sectionHeaders],content:
                        {
                Section(content: {}, header: {
                    Text("section header 一")
                        .font(.largeTitle)
                        .foregroundStyle(.blue)
                        .frame(width: UIScreen.main.bounds.width,height: 100,alignment: .leading)
                })
                ForEach(0..<41){
                    index in
                    Rectangle()
                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<255)/255.0, green: CGFloat.random(in: 0..<255)/255.0, blue: CGFloat.random(in: 0...255)/255.0, alpha: 0.9)))
                        .frame(height: 50)
                }
                //-------
                Section {
                } header: {
                    Text("section header 二")
                        .font(.largeTitle)
                        .foregroundStyle(.blue)
                        .frame(width: UIScreen.main.bounds.width,alignment: .leading)
                }
                ForEach(0..<41){
                    index in
                    Rectangle()
                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<255)/255.0, green: CGFloat.random(in: 0..<255)/255.0, blue: CGFloat.random(in: 0...255)/255.0, alpha: 0.9)))
                        .frame(height: 50)
                }
            })
            .padding(.leading,6)
            .padding(.trailing,6)
            .background(.gray)
        }.background(.blue)
    }
}
#Preview {
    GridViewBootcamp()
}

作用图:

SwiftUI从入门到精华

总结:LazyVGrid我们看到这个单词有个Lazy懒加载的意思,它的内部加载item简略来说,便是当视图需求时,才会履行item内容烘托功用,展现UI上。也就这点留意。

**SafeArea**安全区域:

import SwiftUI
struct SafeAreaBootcamp: View {
    var body: some View {
        GeometryReader{
            src in
            Rectangle()
                .fill(.blue)
                .frame(maxWidth: .infinity,
                       maxHeight: .infinity)
        }
    }
}
#Preview {
    SafeAreaBootcamp()
}

作用图:

SwiftUI从入门到精华

能够看到上下边距存在安全区域的,假如禁用安全区域,运用 ignoresSafeArea(.all) 能够去掉。

代码如下:

SwiftUI从入门到精华

最终说说SwiftUI函数表达

上上代码:


import SwiftUI
struct ExtractFunctionsBootcamp: View {
    @State var bgc:Color = .red
    var body: some View {
        normolView
    }
    var normolView : some View {
        setUI()
    }
    func chageColor() -> Void {
        self.bgc = .red
    }
    func setUI()->some View {
        return ZStack{
            bgc
                .ignoresSafeArea(.all)
            VStack(spacing: 20, content: {
                Text("Hello, World!")
                    .font(.largeTitle)
                Button(action: {
                    bgc = .brown
                }, label: {
                    Text("Button")
                        .font(.largeTitle)
                        .foregroundStyle(.white)
                })
                Button {
                    self.chageColor()
                } label: {
                    Image(systemName: "button.horizontal.top.press")
                        .resizable()
                        .foregroundColor(.white)
                        .aspectRatio(contentMode: .fill)
                        .frame(width: 50,height: 50)
                }
            })
        }
    }
}
#Preview {
    ExtractFunctionsBootcamp()
}

其实函数表达跟我们swift语法糖相同;func 命名;这点和swift语法糖没什么区别。

总结(说说我的感想)

优点:

简洁性:Swift,SwiftUI语法简洁,编写代码变得更加简单和快速。

安全性:是一种类型安全的编程言语,能够在编译时检测类型过错,这帮助我们防止许多常见的过错,提高代码的质量和可靠性

互操作性:它与Objective-C言语无缝互衔接,是的OC与swift代码混编变的更加快捷。

说完优点在说缺点

功用限制:尽管SwiftUI供给了许多常见的UI组件,但与UIKit比较,功用依然相对有限。在某些杂乱的界面需求下,或许需求运用UIKit来完成。

过错提示不清晰:有时SwiftUI, SwiftUI的过错提示或许不行清晰,导致难以定位问题。

UIkit与SwiftUI缺少无缝兼容:两者兼容性不行抱负,这在事务开发中,你或许才能发现。

现在苹果与市面很多使用也在运用Swift,SwiftUI开发使用,这们言语在使用中占有读也是成倍增长。

路漫漫其修远兮,吾将上下而求索

后续更新中……….