SwiftUI 动画新技能,让你的应用「活」起来!

这里每天分享一个 iOS 的新知识,快来关注我吧

前言

在 SwiftUI 中,symbolEffect() 修饰符为 SF Symbols 提供了内置的动画效果,使得在应用中添加好看的动画变得非常容易。通过这些新特性,我们可以实现令人愉悦的用户体验,而且只需极少的代码量。

让我们来看看如何使用这些动画效果,以及如何在应用中实现一些有趣的动画。

基本动画效果

例如,我们可以为一个狗狗图标添加轻柔的上下弹跳效果,每当用户点击按钮时,图标就会做出响应:

css 复制代码
struct ContentView: View {
    @State private var petCount = 0
    var body: some View {
        Button {
            petCount += 1
        } label: {
            Label("Pet the Dog", systemImage: "dog")
        }
        .symbolEffect(.bounce, value: petCount)
        .font(.largeTitle)
    }
}

效果:

多层动画

除了基本动画,我们还可以利用 SF Symbols 的多层特性实现更复杂的效果。默认情况下,多个图层会单独进行动画处理,比如 "mail.stack" 这样的图标可以产生波浪般的效果:

css 复制代码
struct ContentView: View {
    @State private var isFavorite = false
    var body: some View {
        Button {
            isFavorite.toggle()
        } label: {
            Label("Activate Inbox Zero", systemImage: "mail.stack")
        }
        .symbolEffect(.bounce.down, value: isFavorite)
        .font(.largeTitle)
    }
}

效果:

高级动画效果

对于能够支持 iOS 18 或更高版本的应用,我们可以使用.rotate动画来让图标旋转。这在带有箭头等元素的图标上效果特别好。比如,让刷新箭头在点击时旋转:

css 复制代码
struct ContentView: View {
    @State private var animate = false
    var body: some View {
        Button {
            animate.toggle()
        } label: {
            Image(systemName: "arrow.clockwise.square")
                .symbolEffect(.rotate, value: animate)
                .font(.largeTitle)
        }
    }
}

自定义动画速度和次数

SwiftUI 提供了多种动画变体,你甚至可以通过额外选项自定义动画速度和重复次数。例如,下列代码以 3 倍速重复 3 次地动画符号:

css 复制代码
struct ContentView: View {
    @State private var isFavorite = false
    var body: some View {
        Button {
            isFavorite.toggle()
        } label: {
            Label("Activate Inbox Zero", systemImage: "mail.stack")
        }
        .symbolEffect(.bounce, options: .speed(3).repeat(3), value: isFavorite)
        .font(.largeTitle)
    }
}

效果:

变量颜色动画

变量颜色动画特别强大,因为 SF Symbols 可以控制每层动画的显示方式。.variableColor.iterative 会逐层着色,而 .variableColor.cumulative 会累计地添加颜色。此外,你可以为这些动画添加reversing,使动画向前播放后再倒退。

less 复制代码
struct ContentView: View {
    @Stateprivatevar animationsRunning = false
    var body: some View {
        Button("Start Animations") {
            withAnimation {
                animationsRunning.toggle()
            }
        }
        VStack {
            HStack {
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.iterative, value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.cumulative, value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.reversing.iterative, value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.reversing.cumulative, value: animationsRunning)
            }
            HStack {
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.iterative, options: .repeating, value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.cumulative, options: .repeat(3), value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.reversing.iterative, options: .speed(3), value: animationsRunning)
                Image(systemName: "square.stack.3d.up")
                    .symbolEffect(.variableColor.reversing.cumulative, options: .repeat(3).speed(3), value: animationsRunning)
            }
        }
        .font(.largeTitle)
    }
}

效果:

使用内容过渡

如果你只想对标签的内容进行更换,而保持视图不变,建议使用 contentTransition() 修饰符。例如,可以通过 .replace 过渡效果让一个图标淡出而另一个图标出现:

css 复制代码
struct ContentView: View {
    @Stateprivatevar isFavorite = false
    var body: some View {
        VStack {
            Button {
                withAnimation {
                    isFavorite.toggle()
                }
            } label: {
                Label("Toggle Favorite", systemImage: isFavorite ? "checkmark" : "heart")
            }
            .contentTransition(.symbolEffect(.replace))
        }
        .font(.largeTitle)
    }
}

效果:

通过以上例子,可以看到 SwiftUI 提供的 SF Symbols 动画是非常强大和灵活的。

无论是简单还是复杂的应用场景,你都能找到合适的动画来增强用户体验。特别是对于没有设计经验的独立开发者来说,这是一个非常好的选择。

这里每天分享一个 iOS 的新知识,快来关注我吧

本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
看浪的路人17 小时前
第6讲:Streaming 优化——告别“转圈圈“的用户体验
ios·iphone·xcode
传奇开心果编程1 天前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
瓦瓦gogo1 天前
第一次了解 iOS 开发:从 Swift、SwiftUI 到公共组件
ios·swiftui·swift
Liben2 天前
Weex开发踩坑记录
android·前端·ios
season_zhu2 天前
Skills For Real Engineers 系列之三:需求聊清楚了,怎么一步步走主流程,做到交付?
ios·ai编程
茶底世界之下2 天前
窗边花瓶太暗?用 Awaking 看提亮室内的代价
ios
2501_915909062 天前
Windows 上用 VS Code 调试 iPhone 真机 App,KXBuild 断点、崩溃定位实操
ide·windows·vscode·ios·iphone·个人开发·敏捷流程
2501_916007472 天前
抓包工具功能对比,TraceEagle、Charles、Fiddler、Wireshark、mitmproxy 差别
前端·网络协议·ios·adb·https·fiddler·wireshark
青峰讲运维2 天前
OpenStack 存储深度解析|Cinder 块存储 + Swift 对象存储原理与完整实操(Yoga)
开发语言·openstack·swift
2501_915106322 天前
Windows 上开发 Unity iOS,使用 KXBuild 进行真机调试、性能采样与打包 ipa
windows·vscode·unity·ios·个人开发·swift·敏捷流程