每次调用方法它都返回自身的this,妥妥的函数式编程
import SwiftUI
struct ContentView: View {
var body: some View {
// z轴堆叠 还有 HStack
VStack(alignment:.center, content: {
// 还能作用的 Image 上
Image(systemName: "globe").font(.largeTitle).bold(true)
Circle()
Text("Welcom Stanford CS193p").font(.largeTitle).bold(true)
}
).padding()
}
}
#Preview {
ContentView()
}Text("Welcom Stanford CS193p")
.font(.largeTitle)
.bold(true)
.foregroundStyle(.green)试一下,VStack其实也是个 View,效果结果是 VStack 里的内容都设置了
.font(.largeTitle)
VStack(alignment:.center, content: {
Image(systemName: "globe")
Circle()
Text("Welcom Stanford CS193p")
}).padding().font(.largeTitle)但是这个 .padding() 就不是,它是只作用于 VStack 的,如
Text 想要 padding 就要自己设置。
两者是不同的,一个先padding再设置背景色,一个先设置背景色在padding。
后padding的,边框和content padding出的间隔 没有颜色。而先padding后设置背景色就有。
Text("Welcom Stanford CS193p").padding().background(.green)
Text("Welcom Stanford CS193p").background(.green).padding()import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges
peges
peges
peges
}
}
var peges: some View {
HStack{
Circle().foregroundStyle(.green)
Circle().foregroundStyle(.yellow)
Circle().foregroundStyle(.blue)
Circle().foregroundStyle(.yellow)
}
}
}
#Preview {
ContentView()
}改造成函数
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(color:[.green, .blue, .blue, .red])
peges(color:[.green, .blue, .red, .red])
peges(color:[.yellow, .blue, .yellow, .green])
peges(color:[.yellow, .green, .yellow, .red])
}
}
func peges(color:Array<Color>)-> some View {
HStack{
Circle().foregroundStyle(color[0])
Circle().foregroundStyle(color[1])
Circle().foregroundStyle(color[2])
Circle().foregroundStyle(color[3])
}
}
}
#Preview {
ContentView()
}使用 Foreach
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(colors: [Color.green, Color.blue, Color.blue, Color.red])
peges(colors: [Color.green, Color.blue, Color.red, Color.red])
peges(colors: [Color.yellow, Color.blue, Color.yellow, Color.green])
peges(colors: [Color.yellow, Color.green, Color.yellow])
}
}
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
Circle().foregroundStyle(colors[index])
}
}
}
}
#Preview {
ContentView()
}import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(colors: [Color.green, Color.blue, Color.blue, Color.red])
peges(colors: [Color.green, Color.blue, Color.red, Color.red])
peges(colors: [Color.yellow, Color.blue, Color.yellow, Color.green])
peges(colors: [Color.yellow, Color.green, Color.yellow, Color.green])
}
}
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10).aspectRatio(1, contentMode: .fit)
.foregroundStyle(colors[index])
}
HStack {
VStack {
Circle().fill(.green)
// Color.primary 在深色模式下为白色 在正常模式下为黑色
// stroke 绘制边框会将边框宽度 1/2 放到内部 1/2 放外部 影响整体大小
Circle().stroke(Color.primary, lineWidth: 3).fill(.white)
}
VStack {
// strokeBorder 绘制边框 整体宽度在内部 不影响整体大小
Circle().strokeBorder(Color.primary, lineWidth: 3).aspectRatio(1 ,contentMode: .fit)
Circle()
}
}
}
}
}
#Preview {
ContentView()
}import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(colors: [Color.green, Color.blue, Color.blue, Color.red])
peges(colors: [Color.green, Color.blue, Color.red, Color.red])
peges(colors: [Color.yellow, Color.blue, Color.yellow, Color.green])
peges(colors: [Color.yellow, Color.green, Color.yellow, Color.green])
}
}
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10).aspectRatio(1, contentMode: .fit)
.foregroundStyle(colors[index])
}
HStack {
VStack {
Circle().fill(.green)
// Color.primary 在深色模式下为白色 在正常模式下为黑色
// stroke 绘制边框会将边框宽度 1/2 放到内部 1/2 放外部 影响整体大小
Circle().stroke(Color.primary, lineWidth: 3).fill(.white)
}
VStack {
// strokeBorder 绘制边框 整体宽度在内部 不影响整体大小
Circle().strokeBorder(Color.primary, lineWidth: 3).aspectRatio(1 ,contentMode: .fit)
// 设置透明度 0 - 1 0为完全透明 1为完全不透明
Circle().opacity(0)
}
}
}
}
}
#Preview {
ContentView()
}剪切代码段,然后 New “xx.swift” from Clipborder
MatchMarkders.swift
import SwiftUI
struct MatchMarkers: View {
var body: some View {
HStack {
VStack {
Circle().fill(.green)
// Color.primary 在深色模式下为白色 在正常模式下为黑色
// stroke 绘制边框会将边框宽度 1/2 放到内部 1/2 放外部 影响整体大小
Circle().stroke(Color.primary, lineWidth: 3).fill(.white)
}
VStack {
// strokeBorder 绘制边框 整体宽度在内部 不影响整体大小
Circle().strokeBorder(Color.primary, lineWidth: 3).aspectRatio(1 ,contentMode: .fit)
// 设置透明度 0 - 1 0为完全透明 1为完全不透明
Circle().opacity(0)
}
}
}
}ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(colors: [Color.green, Color.blue, Color.blue, Color.red])
peges(colors: [Color.green, Color.blue, Color.red, Color.red])
peges(colors: [Color.yellow, Color.blue, Color.yellow, Color.green])
peges(colors: [Color.yellow, Color.green, Color.yellow, Color.green])
}
}
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10).aspectRatio(1, contentMode: .fit)
.foregroundStyle(colors[index])
}
MatchMarkers()
}
}
}
#Preview {
ContentView()
}在 SwiftUI 中,@ViewBuilder 是一个闭包属性包装器(closure property wrapper),它的作用是:
将多个视图构造语句(如 VStack { ... }, HStack { ... },
条件语句 if/else,switch 等)自动“拼接”成一个单一的 View
类型。
SwiftUI 的 View 协议要求 body 属性返回的是 一个 类型(some View),但现实中我们经常需要写多个视图组合在一起,例如:
写了 @ViewBuilder 连 return 都不用写了,会自动处理返回
@ViewBuilder
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10).aspectRatio(1, contentMode: .fit)
.foregroundStyle(colors[index])
}
MatchMarkers2(matches: [Match.exact, Match.inexact, Match.nomatch, Match.exact])
}
}如果swift函数内只有一行,类型和函数返回值类型相同,也不用显式写 return,这只是语法糖。
ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
peges(colors: [Color.green, Color.blue, Color.blue, Color.red])
peges(colors: [Color.green, Color.blue, Color.red, Color.red])
peges(colors: [Color.yellow, Color.blue, Color.yellow, Color.green])
peges(colors: [Color.yellow, Color.green, Color.yellow, Color.green])
}
}
func peges(colors: Array<Color>)-> some View {
HStack{
ForEach(colors.indices, id: \.self) { index in
RoundedRectangle(cornerRadius: 10).aspectRatio(1, contentMode: .fit)
.foregroundStyle(colors[index])
}
MatchMarkers(matches: [Match.exact, Match.inexact, Match.nomatch, Match.exact])
}
}
}
#Preview {
ContentView()
}MatchMarkers.swift
import SwiftUI
enum Match {
case nomatch
case exact
case inexact
}
struct MatchMarkers2: View {
// var matches: [Match]
var matches: Array<Match>
var body: some View {
HStack {
VStack {
matchMarker(peg: 0)
matchMarker(peg: 1)
}
VStack {
matchMarker(peg: 2)
matchMarker(peg: 3)
}
}
}
func isNotNomatch(matchItem: Match)-> Bool {
return matchItem != Match.nomatch
}
func matchMarker(peg: Int) -> some View {
let exactCount = self.matches.count(where: { matchItem in matchItem == Match.exact})
// 传递函数写法:
// let foundCount = self.matches.count(where: isNotNomatch)
// foundCount 改为内联写法:
// let foundCount = self.matches.count(where: {(matchItem: Match) -> Bool in
// matchItem != Match.nomatch
// })
// 极限简化后写法用 $number 代表函数参数
// let foundCount = matches.count(where: {$0 != Match.nomatch})
// 终极简化
let foundCount = matches.count{ $0 != Match.nomatch }
// 普通模式下 如果 exactCount > peg 则填充为黑色
// 如果 foundCount > peg 边框为黑色当白钉子
// 填充为白 边框为白则表示没有钉子
return Circle().fill(exactCount > peg ? Color.primary : Color.clear)
.strokeBorder(foundCount > peg ? Color.primary : Color.clear, lineWidth: 2)
.aspectRatio(1, contentMode: ContentMode.fit)
}
}
#Preview {
// exactCount为1 foundCount为3 一个黑钉 两个白钉
MatchMarkers2(matches: [Match.exact, Match.inexact, Match.nomatch, Match.inexact])
}func isNotNomatch(matchItem: Match)-> Bool {
return matchItem != Match.nomatch
}
let exactCount = self.matches.count(where: { matchItem in matchItem == Match.exact})
// 传递函数写法:
// let foundCount = self.matches.count(where: isNotNomatch)
// foundCount 改为内联写法:
// let foundCount = self.matches.count(where: {(matchItem: Match) -> Bool in
// matchItem != Match.nomatch
// })
// 极限简化后写法用 $number 代表函数参数
// let foundCount = matches.count(where: {$0 != Match.nomatch})
// 终极简化
let foundCount = matches.count{ $0 != Match.nomatch }