SwiftUI Tips 004:奇妙而强大的修饰符 (modifier)

Easter79
• 阅读 704

在 SwiftUI 中,修饰符的功能类似于 CSS,用来在应用布局中定位和配置视图,如修改视图的大小、背景、添加动画、添加手势等等。View 协议通过扩展提供了大量的修饰符,它们以协议方法的形式给出,同时提供了默认实现。以我们熟悉的 frame() 为例,来看看它的声明:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)extension View {    /// Positions this view within an invisible frame having the specified    /// width and/or height.    ///    /// Use this method to specify a fixed size for a view's width,    /// height, or both. If you only specify one of the dimensions, the    /// resulting view assumes this view's sizing behavior in the other    /// dimension.    ///    /// ...    @inlinable public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> some View    /// This function should never be used.    ///    /// It is merely a hack to catch the case where the user writes .frame(),    /// which is nonsensical.    @available(*, deprecated, message: "Please pass one or more parameters.")    @inlinable public func frame() -> some View}

类似的声明还有很多。可以说,修饰符在 SwiftUI 中起着举足轻重的作用。

与 CSS 类似,修饰符的效果具有传递性,也就是说,父视图上使用的修饰符也会影响到其所有子视图,除非子视图显式的调用修饰符来覆盖这种效果,如下所示:

struct ContentView: View {    var body: some View {        VStack {            Text("Hello, world!").padding()            Text("Hello, iOS 14").font(.body)       // 覆盖 VStack 的字体大小设置        }        .font(.system(size: 60))    }}

SwiftUI Tips 004:奇妙而强大的修饰符 (modifier)

一般情况下,每个修饰符的作用是特定的,如 font() 用于修改字体大小, frame() 用于修改视图大小。然而一个视图通常会有很多属性,同时修改多个属性时需要依赖于多个修饰符,这时我们就可以通过链式调用的方式将这些修饰符串连起来,以完成对同一个视图的多重修饰。如下代码所示:

struct ContentView: View {    var body: some View {        VStack {            Text("Hello, world!")                .foregroundColor(.blue)                .padding(.all, 20)                .border(Color.yellow, width: 1)        }        .font(.system(size: 60))    }}

SwiftUI Tips 004:奇妙而强大的修饰符 (modifier)

之所以能以链式的方式调用修饰符,是因为每个修饰符方法的返回值是 some View (如上面 frame() 的声明),仍然是一个视图,所以可以在新的视图的基础上继续调用修饰符。

需要注意的是,在链式调用的过程中,修饰符的顺序会对实际效果产生影响。相同的两个修饰符以不同的顺序调用,呈现的结果可能是不一样的。我们交换一下上面代码中 padding() 和 border() 的位置:

struct ContentView: View {    var body: some View {        VStack {            Text("Hello, world!")                .foregroundColor(.blue)                .border(Color.yellow, width: 1)                .padding(.all, 20)        }        .font(.system(size: 60))    }}

SwiftUI Tips 004:奇妙而强大的修饰符 (modifier)

可以看到边框位置的明显变化。实际上,如果我们稍微探索一下每一次调用修饰符所产生的视图,就会发现两者所生成的视图类型并不相同,我们将代码稍作修改:

struct ContentView: View {    var body: some View {        VStack {            createText()        }        .font(.system(size: 60))    }        func createText() -> some View {        let text = Text("Hello, world!")            .foregroundColor(.blue)            .border(Color.yellow, width: 1)            .padding(.all, 20)        return text    }}

在第 14 行打上断点,分别运行,并通过 po type(of: text) 来查看 text 的类型,可以得到如下结果:

// Text("Hello, world!").foregroundColor(.blue).border(Color.yellow, width: 1).padding(.all, 20) 的类型SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.Text, SwiftUI._PaddingLayout>, SwiftUI._OverlayModifier<SwiftUI._ShapeView<SwiftUI._StrokedShape<SwiftUI.Rectangle._Inset>, SwiftUI.Color>>>// Text("Hello, world!").foregroundColor(.blue).border(Color.yellow, width: 1).padding(.all, 20) 的类型SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.Text, SwiftUI._OverlayModifier<SwiftUI._ShapeView<SwiftUI._StrokedShape<SwiftUI.Rectangle._Inset>, SwiftUI.Color>>>, SwiftUI._PaddingLayout>

可以看到,两者有不同的嵌套结构。详细的结构我们会在其它 Tip 中分析。SwiftUI 提供了丰富的修饰符,让开发者能尽情地创建生动而奇妙的页面,同时 SwiftUI 还提供了方法让我们可以自定义修饰符,以满足开发者创造的渴望。我们同样也会在另外一个 Tip 中来介绍如何自定义修饰符。

本文分享自微信公众号 - 酷酷的哀殿(kukudeaidian)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
SwiftUI直通车系列(1)—— 视图的布局与组织
SwiftUI直通车系列(1)——视图的布局与组织一、引言    SwiftUI提供了一种更快、更高效也更简单的页面开发方式。我们知道相对于ObjectiveC,Swift语言本身就更加高效简洁,SwiftUI采用了结构化的布局方式,使得应用的界面开发更加直观快速。本系列博客,
Easter79 Easter79
3年前
Swift专题讲解二十一——协议
Swift专题讲解二十一——协议一、引言      协议约定了一些属性与方法,其作用类似Java中的抽象类,Swift中类型通过遵守协议来实现一些约定的属性和方法。Swift中的协议使用protocol关键字来声明。Swift中的协议还有一个十分有意思的特性,协议可以通过扩展来实现一些方法和附加功能。
Easter79 Easter79
3年前
SwiftUI直通车系列(6)—— 使用动画
SwiftUI直通车系列(6)——使用动画   本系列博客是针对SwiftUI开发框架的快速入门介绍,之前系列博客地址:SwiftUI直通车系列(1)——视图的布局与组织(https://my.oschina.net/u/2340880/blog/4529951)SwiftUI直通车系列
Stella981 Stella981
3年前
Android 动画和图形概述
Android提供了非常多强大的API来为UI元素应用动画,及绘制定制的2D和3D图形。下面的部分提供了一个APIs和可用的系统功能的概述,并帮助你确定,对于你的需求而言,哪种方法是最好的。动画Androidframework提供了两种动画系统:属性动画(在Android3.0中引入)和view动画。两种动画系统都是可行的选择,但通常而言
Stella981 Stella981
3年前
JOptionPane修改图标
1.在Linux平台下.JOptionPane会显示Java默认的图标,在window平台不显示图标,如何替换这个图标了?2JOptionPane.setIcon(Icon)修改的是内容区域的icon,而不是左上角的Icon.所以需要通过修改Jdialog/Frame的图标来达到修改默认图标的问题.3.代码:if(JOptio
Wesley13 Wesley13
3年前
Java修饰符类型
修饰符是一种添加到定义以更改其含义的关键字。Java语言有各种各样的修饰符,包括以下两种Java访问修饰符例如:private,protected,public等。Java非访问修饰符例如:static,final等。要使用修饰符,请在类,方法或变量的定义中包含修饰符关键字。修饰符位于语句之前,
Easter79 Easter79
3年前
SwiftUI直通车系列(2)—— 列表视图
SwiftUI直通车系列(2)——列表视图  列表视图的开发中非常常用的页面元素。SwiftUI中也有专门用来渲染列表的元素提供。一、编写行视图   列表实际上是一组行视图的组合,在布局列表视图之前,你首先需要定义好行视图的布局。例如,我们使用一个Image元素和两个Tex
Easter79 Easter79
3年前
SwiftUI 跨组件数据传递
作者:Cyandev,iOS和MacOS开发者,目前就职于字节跳动0x00前言众所周知,SwiftUI的开发模式与React、Flutter非常相似,即都是声明式UI,由数据驱动(产生)视图,视图也会与数据自动保持同步,框架层会帮你处理“绑定”的问题。在声明式UI中不存在命令式地让一个视图变成xxx
融云IM即时通讯 融云IM即时通讯
11个月前
如何实现自定义表情?
1、继承实现协议RCEmoticonTabSource2、在实现的代理方法loadEmoticonView返回View,(返回的以下图中红框区域,里面的视图及逻辑需要自己来添加实现)3、在会话页面viewdidLoad里添加表情包示例代码(Demo源码2中
小万哥 小万哥
8个月前
深入理解 Java 修饰符与封装:访问权限、行为控制与数据隐藏
Java修饰符Java修饰符用于控制类、属性、方法和构造函数的访问权限和行为。它们可以分为两组:1.访问修饰符:public:意味着代码对所有类可访问。private:意味着代码只能在声明的类内部访问。default:意味着代码只能在同一包中访问。prot
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k