Swift UI学习(2)
1.Safe Area
Safe Area(安全区域)是指不与导航栏、标签栏、工具栏或其他视图控制器提供的视图重叠的内容空间。
在SwfitUI 中,为确保开发者创建的视图都被布局到安全区域当中,SwiftUI 同时提供了一些方法和工具让开发者对安全区域有所控制。
下面是iPhone和ipad的安全区域示意图:
注:不同型号上的iPhone和ipad的安全区域可能不同
因为有了Safe Area的存在,我们在进行一些设计时会导致无法铺满整个屏幕,如在进行背景的设计时总会空出一部分的区域,不利于我们进行UI的设计:
可以看到哪怕我让框架尽可能的大也仍然没有铺满背景图片。
SwiftUI针对这个情况专门有一个函数ignoresSafeArea(),他可以让我们忽略安全区域,默认情况下是忽略所有的安全区域,我们也可以单独去设计它可以忽略哪些安全区域。其初始定义如下:
@inlinable public func ignoresSafeArea(_ regions: SafeAreaRegions = .all, edges: Edge.Set = .all) -> some View
可以看到,这个函数中含有两个参数,SafeAreaRegions和edges
对于edges,用来指定忽略的安全区域边缘,如:
.all
:忽略所有安全区域边缘。.top
:忽略顶部安全区域边缘。.bottom
:忽略底部安全区域边缘。.left
:忽略左侧安全区域边缘。.right
:忽略右侧安全区域边缘。
对于SafeAreaRegions,指定要忽略的安全区域区域。这对于在安全区域内放置特定类型的视图或内容非常有用。它包含三种划分:
- container
由设备和用户界面内的容器所定义的安全区域,包括诸如顶部和底部栏等元素。
- keyboard
与显示在视图内容上的任何软键盘的当前范围相匹配的安全区域。
- all(默认)
上述两种安全区域划分的合集
下面我们来讲一下使用该函数时可能出现的一些问题,例如刚才的背景,我们在背景的下面加上忽略安全区域,并且想让文字刚好出现在界面的顶部,这时我们将spacer()添加在下面,点击预览:
可以看到,我们成功的忽略了安全区域,但坏消息是我们的文字也忽略了安全区域,这将导致我们的文字无法显示在视图上。
为了解决这个问题,我们可以使用一个Zstack()将我们的代码扩起来,并将背景色和忽略函数写在Zstack()上。由于Zstack()的特性(自后往前),我们的文字就会出现在屏幕安全区域顶端。
2.Button
Button(按钮)顾名思义,就是一个可以点击的按钮,在swiftui中,按钮是十分重要的一环,它可以帮我们做到许多的交互和设计。
先来看看Button的基本使用,一般而言,我们会使用下面两种输入方式.
Button( //标题 , action: //操作 )
前面只能接收字符串,为文本,不能改变样式。
Button(action: {
// 操作
}) {
// 按钮样式
}
我们也可以不输入action,这样点击下去的按钮不会执行任何操作。
下面看一个简单的使用,
我们设置了一个改变标题的按钮,并将标题设置为一个可变的量(@state声明是可变的变量,后面会讲到),点击按钮后改变标题。
很多时候按钮需要更多样化,来达到美化UI的作用,这时我们就会用到Button的第二种定义,下面设计一个按钮样例:
3.@State
在 SwiftUI 中,视图是由数据(状态)驱动的。每当视图在创建或解析时,都会为该视图和该视图中使用的状态数据之间创建一个依赖关系,每当状态的信息发生变化,有依赖关系的视图会马上翻译出这些变化并重绘,而@State就是一个联系视图和动态数据之间的一个桥梁。
我们在构建变量时往往需要进行视图的更新,@State的作用就是告诉视图这是一个会改变的量,我们需要去观察它的状态并改变视图。
如果我们只是将一个数据类型修改为var(变量),而不在前面加上@State,会发生以下情况:
- 变量的值不会被 SwiftUI 追踪,因此当变量值发生变化时,UI 不会自动更新。
- 尝试访问未被
@State
修饰的变量时,会引发编译器错误下面看一个例子:
这时swift会跳出以下错误:
因为我们访问了一个没有@state类型的变量数据,所以编译器认为这是一条不完整的语句。
此外,@State不光能装饰Int,Double等常规的数据类型,@State几乎可以UI中的任何变量,如:Color,Button,font等
4.function和subviews
我们在构建视图时,为了装饰,一个元素可能就要写好几行,这样我们在进行整体设计时,代码会变得非常多。冗长的代码不利于我们的维护和修改,为此我们需要分化代码,这时就会用到function(函数)和subviews(子视图)。
4.1function
对于function,我们可以将需要修改变量状态的类型放在函数中,如我们设计一个按钮,点击按钮会改变背景颜色。
设计一个按钮的函数:
然后将action中的语句替换为Buttonchange()即可,而且我们可以通过点击这个函数直接找到对应的位置。
这个代码并没有很好的体现函数的简化,但如果一个按钮中有多个操作或者再遇到类似的操作时,我们可以直接调用函数来完成,
4.2subviews
在视图的创建过程中,我们尽管可以使用函数对代码进行简化,但仍然会显得很冗长,这时我们可以将视图分开,即创建多个子视图,在主视图中只保留子视图的名称即可。
如我们将上面的按钮放入一个子视图中,命名为contentLayer,这时我们只需要在主视图里写上子视图的名字即可自动更新。
这时的视图也会更新为刚才我们写在主视图的样子,分子视图的写法可以让我们的代码更有明确性,方便查找和维护。
上面的子视图固然方便,但当我们需要动态的调用子视图时(如将按钮中的数字更换并创造多个类似的按钮)这种时候,我们就需要另一种视图:Extract Subview
这时我们就创建了一个Extract Subview,这个视图中基本含有和我们主视图一样的元素,因此我们也可以称为第二屏幕,我们可以在里面定义一些新的变量,这时我们再调用这个子视图时,它会要求我们对这些变量进行赋值:
创建的变量。
可以看到在主视图中调用这个视图时我们可以对其进行直接的赋值。
注意:视图的名称是可以自定义修改的
我们可以用此进行重复框架但不同细节的创造,这会大大的提升我们的效率。
5.@Binding
我们前面学习了使用Extract Subview来进行代码的分化,但是使用这个方法时会出现一个问题,下面看一个例子:
我们将主视图的Button都放入了Extract Subview创建的视图中,但是我们却无法在这个子视图中调用主视图的变量元素,你可以在创建一个和主视图变量同名的变量,但此变量非彼变量。
这是因为Extract Subview的视图不是主视图的直接子视图,当使用
@State
修饰一个变量时,SwiftUI 会创建一个私有存储,该存储与视图及其所有子视图相关联。当子视图从主视图中提取时,它们不再与主视图的私有存储相关联,因此无法访问
@State
定义的变量。
这时我们就需要用到一个@Binding(绑定),该变量会帮助我们把变量进行绑定,进行视图间的共享。
我们将上面的代码进行完善:
这时我们在主视图的调用中添加了一个$符号,这意味着下面使用@Binding绑定的变量是跟主视图中的backgroundColor变量绑定,且绑定是双向的,@Binding也可以用于非主子视图的绑定,即任意两视图的绑定
注意:一般来说我们绑定的变量名跟主视图的变量名相同,你也可以设置不相同变量名
6.if else 语句
在swift中,我们常用if else 语句来进行条件的判断和执行。在SwiftUI中,我们也常用if else 语句来进行我们所需要的变化。如在Button语句中,我们可以用它来进行判断,在特定条件下会出现特定的图像。
注:toggle表示bool函数在true和false之间切换,即点一下改变一次。
在这份代码中,我们创建了一个变量showCircle,并用if else 语句来进行按下按钮的判断,如果按下按钮时showCircle为真,那么我们就会出现一个圆形,反之则出现一个矩形。
此外,在条件的判断中,我们可以使用 ||(或) ,&&(且),!(非),以及三元运算符: ”?:“来进行代码的优化。
下面重点看一下三元运算符,在我们创建视图的过程中,可能存在只有颜色改变而图片的形状和大小不改变(或只有大小变形状不变)类似的例子,这时我们可以使用三元运算符来简化我们的代码。
简化前:
简化后
这可以大大优化我们的代码量,提高效率。
7.animation
如果你看了上面的代码并尝试运行它,你会发现在你点击按钮的时候画面是瞬间切换的。尽管有时我们会需要这个瞬间切换,但大多数时候为了更好的体验和美观,我们往往会给这个"转场"添加动画(animation),这会使得我们的画面更具有生动感。
一般而言我们会使用下面两种动画修改器:
- **withAnimation(_: )**:应用动画到视图树中所有支持动画的视图。
- **animation(_:, value: )**:将动画应用于单个视图或属性。
我们下面使用**withAnimation(_: ) **来修改之前的代码:
.default表示使用默认的动画模式
这时我们查看视图,在点击按钮时我们可以看到下面两个图形,且它们之间有动画的变化。
我们还可以通过其它的设置来达到不同的动画效果。
- **duration(_: )**:设置动画持续时间。
- **delay(_: )**:设置动画延迟时间。
- **repeatCount(_: )**:设置动画重复次数。
- **autoreverse(_: )**:设置动画是否自动反转。在它们之间切换时产生动画效果。
- rotationEffect(_: ):设计点旋转,可以设计切换时的旋转角度。
下面看一个示例:
我们将刚才的按钮动画修改为永远的重复和一直进行来回翻转(true表示来回翻转,而false则会只“有去无回”的重复) ,这时你点击按钮就会发现动画一直在来回变化。
此外,动画还有一个比较有意思的点是,我们可以限制动画过渡的速度变化情况,如先慢后块还是先快后慢的变化,亦或者是线性的变化。下面看一段代码:
你可能很难在动画的短促变化中看清这些变化,我们可以通过加长动画的变化时间来更清晰的观察到这些变化,在每段代码的后面加上(duration:_)并加上一个较长的变化时间即可,可自行尝试。
8.transition
在SwiftUI中,transition决定了某个View如何插入到视图栈中,或者如何在视图栈中移除。transition自身并没有任何效果, 需要配合动画一起使用,举个例子:
在上面这段代码中,我们设计了一个点击就将按钮淡出的transition,可以看到他会之间的消失,为了界面的美化,这时我们就会加上以下代码:
.animation(.easeInOut)
此外,transition中还有别的修饰方式,一般包括如下选项:
- modifier:用于指定过渡效果的修饰符,例如
.opacity
(淡入淡出)、.slide
(滑动)和.scale
(缩放)。 - duration:指定过渡动画持续时间的可选参数,以秒为单位。
- animation:指定过渡动画缓动效果的可选参数,例如
.easeInOut
(平滑、自然的运动)和.spring
(弹簧效果)。
版权归原作者 kkzjyy 所有, 如有侵权,请联系我们删除。