SwiftUI基础控件

1,814 阅读6分钟

表单

image.png

导航栏

image.png

提示:很容易认为修饰符应该附加到 NavigationStack的末尾,但实际上是附加到Form的末尾。原因是导航堆栈能够在程序运行时显示许多视图,因此通过将标题附加到导航堆栈内的内容,我们允许 iOS 自由更改标题。

  • toolbar 工具栏

toolbar()让我们可以指定视图的工具栏项。这些工具栏项可能出现在屏幕上的各个位置 - 顶部的导航栏中、底部的特殊工具栏区域等。

image.png

  • onChange 监听属性变化
.onChange(of: xxx ) { oldValue, newValue in

    // 特定值发生变化,它就会运行我们选择的闭包 

}

image.png

按钮 & 属性包装器 @State

image.png

Button("删除", action: executeDelete)

Button("删除", role: .destructive) {
    ...
}
.buttonStyle(.borderedProminent)  // 样式风格
.tint(.blue)  // 颜色

Button("编辑", systemImage: "pencil") {
    //...
}

自定义按钮


Button {
    //...
} label: {
  
    // 自定义控件 样式 布局
    Label("Edit", systemImage: "pencil")
        .padding()
        .foregroundStyle(.white)
        .background(.red)
}
  • 更改属性

由于Swift的结构体是值类型(固定的),不允许修改其属性。若要更改属性,Swift提供了@State允许我们这个限制:@State允许 SwiftUI 将该值单独存储在可以修改的位置。

@State 会自动监视更改,并且当发生某些情况时它会自动重新调用该body属性。它将重新加载您的 UI 以反映更改后的状态,这是 SwiftUI 工作方式的基本功能。

@State专为存储在一个视图中的简单属性而设计。Apple 建议我们为这些属性添加访问控制private

当然,我们可以使用类来代替———它们可以自由修改属性。但是,SwiftUI 会频繁地销毁和重新创建您的结构体,因此保持它们小而简单对于性能非常重要。使用结构体是 出于性能的考虑。

文本框 & 双向绑定

  • 视图是其状态的函数

image.png

  • 双向绑定

使用符号$@State 组合

输入框绑定文本属性 => 输入框显示文本属性,同时,输入框编辑也会更新属性。

我们在属性名前写一个美元符号。这告诉 Swift 它应该读取属性的值,但也应该在发生任何更改时将其写回。

  • 格式

image.png

  • 键盘的隐藏

需要用到第二个属性包装器:@FocusState。这与常规的@State完全相同,只不过它是专门为处理 UI 中的输入焦点而设计的。

image.png

image.png

在循环中创建视图 ForEach

想要在循环内创建多个 SwiftUI 视图是很常见的。例如,想要循环遍历一组名称,并让每个名称都是一个文本视图。SwiftUI 为此目的提供了一个专用的视图类型,称为ForEach。 这可以循环数组和范围,根据需要创建尽可能多的视图。ForEach将为它循环的每个项目运行一次闭包,并传入当前循环项目。

image.png

选择器 Picker

image.png

其中,id: \.self部分很重要。因为 SwiftUI 需要能唯一地识别屏幕上的每个视图,以便它可以检测到事物何时发生变化。这里,id: \.self意味着“字符串本身是唯一的”,如果您向options数组添加重复的字符串,可能会遇到问题

  • 设置风格

image.png

堆栈视图

VStack 垂直排列布局

image.png

  • 间距
VStack(spacing: 30){

}
  • 对齐方式
VStack(alignment: .leading) { 

}  
  • Spacer() 占用/排挤

将堆栈的内容推到一侧。可添加多个

image.png

HStack 水平排列布局

同理

ZStack 重叠布局

按深度排列控件——它使视图重叠。

image.png

没有间距的概念,因为视图重叠,但它确实有对齐。

image.png

颜色

SwiftUI 为我们提供了一系列渲染颜色的功能,并且做到了既简单又强大。

image.png

  • 安全区域

白色空间为故意留空,因为 Apple 不希望重要内容被其他 UI 功能或设备上的任何圆角遮挡。所以,剩下的部分——整个中间的空间——被称为 “安全区域”,你可以自由地绘制它,而不用担心它可能被 iPhone 上的凹口剪掉。 白色空间的大小取决于您的设备,但在具有 Face ID 的 iPhone(例如 iPhone 15)上,您会发现动态岛区域(顶部的胶囊形区域)和主页指示器(水平方向)底部的条纹)保持未着色。

如果需要,你可以设置忽略安全区

image.png

重要的内容不要放置在安全区域之外,这一点至关重要。如果您的内容只是装饰性的(就像我们这里的背景颜色一样),那么将其扩展到安全区域之外是可以的。

  • frame

颜色会自动占据所有可用空间,但您也可以使用修饰符frame()来请求特定尺寸;还可以根据所需的布局指定最小和最大宽度和高度。

Color.red
    .frame(width: 200, height: 200) 
    
Color.red
    .frame(minWidth: 200, maxWidth: .infinity, maxHeight: 200)  

事实上,Color.red 本身就是一个视图,这就是为什么它可以像形状和文本一样使用。

  • 内置颜色

如Color.blue、Color.green、Color.indigo

  • 语义颜色

颜色不说明它们包含什么色调,而是描述它们的用途。

如,Color.primary是 SwiftUI 中文本的默认颜色,并且将是黑色或白色,具体取决于用户的设备是在浅色模式还是深色模式下运行。还有Color.secondary,根据设备的不同,它也是黑色或白色,但现在具有轻微的透明度,因此其背后的一些颜色会透过。

  • 自定义颜色

Color(red: 1, green: 0.8, blue: 0)

  • 渐变

image.png

SwiftUI 为我们提供了 四种 可供使用的渐变,就像颜色一样,它们中的大多数也是可以在我们的 UI 中绘制的视图。

渐变由几个部分组成:

  1. 显示一系列颜色
  2. 尺寸和方向信息
  3. 要使用的渐变类型

一、线性渐变:朝一个方向移动

LinearGradient(colors: [.white, .black], startPoint: .top, endPoint: .bottom) 

可以提供渐变停止点,让您指定颜色以及颜色应该沿渐变多远使用

LinearGradient(stops: [

    .init(color: .white, location: 0.45),

    .init(color: .black, location: 0.55),

], startPoint: .top, endPoint: .bottom)  

二、径向渐变:以圆形形状向外移动。因此我们不指定方向,而是指定开始和结束半径——颜色应开始和停止变化距离圆心多远。

RadialGradient(colors: [.blue, .white], center: .center, startRadius: 20, endRadius: 200)

image.png

三、角度渐变,(圆锥形或圆锥形渐变)

这样颜色会围绕一个圆圈循环,而不是向外辐射,并且可以产生一些美丽的效果。

AngularGradient(colors: [.red, .yellow, .green, .blue, .purple, .red], center: .center) 

image.png

四、渐变背景

您无法对其进行任何控制,并且您也只能将它们用作背景和前景样式,而不是单独的视图。 只需在任何颜色后添加即可创建此渐变.gradient

image.png

弹窗

状态属性控制弹窗。提示:双向数据绑定,当警报解除时 SwiftUI 会自动设置回 false,不需要手动处理。 image.png

image.png

小技巧

  • 数组
var arr = [2,6,4,8,9,3]

arr.shuffled()  // 进行 数组随机排序
  • 文本
// 粗体
Text("提示").font(.subheadline.weight(.heavy))
// 大标题
Text("提示").font(.largeTitle.weight(.semibold))
// 小标题 
Text("提示").font(.title3.weight(.bold))  
  • 圆角处理
.clipShape(.capsule)  // 胶囊

.clipShape(.rect(cornerRadius: 10))  // 圆角
  • 阴影处理

.shadow(radius: 12)

  • 最大宽高

.frame(maxWidth: .infinity, maxHeight: .infinity)