当前位置: 首页 > article >正文

白玉微瑕:闲谈 SwiftUI 过渡(Transition)动画的“口是心非”(下)

在这里插入图片描述

概述

秃头小码农们都知道,SwiftUI 不仅仅是一个静态 UI 构建框架那么简单,辅以海量默认或自定义的动画和过渡(Transition)特效,我们可以将 App 界面的绚丽升华到极致。

在这里插入图片描述

不过,目前 SwiftUI 中的过渡(Transition)动画在某些“敏感”场景中会有让人意想不到的效果,我们如何随机应变回归本源呢?本篇由此应运而生。

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

  • 概述
  • 3. Transition 动画之“怪癖”
  • 4. 暗度陈仓:用动画(Animation)代替过渡(Transition)
  • 总结

本文示例代码测试环境:macOS 15.2 + Xcode 16.1

百闻不如一见,那小伙伴们还等什么呢?让我们马上开始 Transition 动画除虫大冒险吧!

Let‘s go!!😉


3. Transition 动画之“怪癖”

虽然 Transition 动画在大多数情况下表现的都十分惊艳,但“金无足赤,人无完人”,Transition 动画在某些场景下也会“选择性失灵”。

其中一种场景就是:若视图同时包裹在 NavigationStack 和 Form(或 List)容器内,则视图的插入 Transition 过渡动画会消失不见,变为“鸟迹虫丝”。

在下面的代码中,我们测试的两枚绿色圆形分别放在了不同的容器中:

  1. 顶部的圆形放在 NavigationStack 和 List 中;
  2. 底部的圆形只放在了 NavigationStack 中;
struct ContentView: View {
    
    @State var magic = false

    var body: some View {
        NavigationStack {
            VStack(alignment: .leading) {
                List {
                    Section("同时嵌入在 NavigationStack 或 List 中") {
                        VStack {
                            if magic {
                                Circle()
                                    .foregroundStyle(.green)
                                    .frame(width: 100, height: 100)
                                    .transition(.scale)
                            }
                            
                            Spacer()
                            Text("没有插入,只有消失时的缩放过渡动画")
                        }
                        .frame(height: 200)
                    }
                }
                .listStyle(.plain)
                
                
                Divider()
                
                Section("只嵌入在 NavigationStack 中") {
                    VStack {
                        if magic {
                            Circle()
                                .foregroundStyle(.green)
                                .frame(width: 100, height: 100)
                                .transition(.scale)
                        }
                        
                        Spacer()
                        Text("插入和消失时皆有缩放过渡动画")
                    }
                    .frame(height: 200)
                }
                
                Button("Magic") {
                    withAnimation(.bouncy) {
                        magic.toggle()
                    }
                }
            }
            .padding()
            .navigationTitle("过渡动画“怪癖”演示")
        }
    }
}

运行结果如下所示:

在这里插入图片描述

可以看到:顶部圆形没有插入过渡动画,而底部圆形的过渡动画完美无缺。

注意,上面代码中两个圆形视图上的过渡动画代码都是完全一致的,不存在特殊对待的情况。


若想进一步了解 SwiftUI 中动画的各种高级操作技能,请小伙伴们猛戳下面的链接观赏进阶内容:

  • SwiftUI 动画进阶:实现行星绕圆周轨道运动
  • 如何为 Apple 官方 SwiftUI 示例中的图表元素加上首显动画?
  • SwiftUI4.0有趣的动画升级:新iOS16视图内容过渡动画
  • SwiftUI如何模拟视图发光增大的动画效果
  • 阅读第三方源代码解决SwiftUI弹出视图无动画以及List被诡异重建的问题

4. 暗度陈仓:用动画(Animation)代替过渡(Transition)

对于上面过渡(Transition)动画的这种“怪癖”,我们有一些解决办法来绕过它。不过,它们大多比较复杂,那么有没有简单的方法呢?

答案是肯定的!

其实,SwiftUI 中的普通动画与过渡动画是非常类似的,从本质上来说:在播放动画时前者会保持视图“稳定”,而后者会导致视图被插入或删除。

有了这一思路,我们就可以轻松的将过渡动画转换为普通的动画了:

Section("同时嵌入在 NavigationStack 或 List 中") {
    VStack {
        Circle()
            .foregroundStyle(.green)
            .frame(width: 100, height: 100)
            .scaleEffect(magic ? .init(width: 1, height: 1) : .zero)
        
        Spacer()
        Text("利用普通动画解决过渡动画丢失的问题")
    }
    .frame(height: 200)
}

从上面的代码可以看出,我们将原先绿色 Circle 上的过渡动画转换成了在视图尺寸上缩放的普通动画效果:

在这里插入图片描述

同样,对于博文开头 WorryObject 选择过渡动画缺失的情况,我们也可以如法炮制:

Image(systemName: "checkmark.circle.fill")
    .foregroundStyle(.green.gradient)
    .font(.title3.bold())
    .scaleEffect(selectingWorryObjectID == wObject.oid ? .init(width: 1, height: 1) : .zero)
    .matchedGeometryEffect(id: 1, in: ns, isSource: selectingWorryObjectID == wObject.oid)

最后运行一下,在 Xcode 预览中欣赏一番我们的最终成果吧:

在这里插入图片描述

现在,对于那些 SwiftUI 中过渡动画失灵又无计可施的撸码场景我们也可以轻松应对了,棒棒哒!💯


想要进一步系统地学习 Swift 开发的小伙伴们,可以来我的《Swift 语言开发精讲》专栏逛一逛哦:

在这里插入图片描述

  • 《Swift 语言开发精讲》

总结

在本篇博文中,我们进一步讨论了 SwiftUI 过渡动画在什么场景下可能会掉链子,并用一招将其彻底驯服。

感谢观赏,再会啦!😎


http://www.kler.cn/a/515224.html

相关文章:

  • 论文速读|NoteLLM: A Retrievable Large Language Model for Note Recommendation.WWW24
  • 解锁C# EF/EF Core:从入门到进阶的技术飞跃
  • 数据结构:二叉树
  • YOLOv8改进,YOLOv8检测头融合DSConv(动态蛇形卷积),并添加小目标检测层(四头检测),适合目标检测、分割等
  • 医学图像分析工具09.1:Brainstorm安装教程
  • Text2SQL 智能报表方案介绍
  • 无人机 PX4 飞控 | PX4源码添加自定义参数方法并用QGC显示与调整
  • 使用EVE-NG-锐捷实现静态路由
  • jvm_threads_live_threads 和 jvm_threads_states_threads 这两个指标之间存在一定的关系,但它们关注的维度不同
  • 【Go面试】工作经验篇 (持续整合)
  • 通俗的讲,网络爬虫到底是什么?
  • HQChart使用教程30-K线图如何对接第3方数据45- DRAWRADAR数据结构
  • jvm G1 垃圾收集日志分析示例(GC)
  • ubuntu终端当一段时间内没有程序运行时,自动关闭终端。
  • Golang笔记—— error 和 panic
  • 在 Ubuntu 22.04 上安装 Kubernetes(Kubeadm 安装方式)
  • STM32 ST7735 128*160
  • 数据链路层协议
  • FluentCMS:基于 ASP.NET Core 和 Blazor 技术构建的开源CMS内容管理系统
  • 代码随想录——串
  • mysql 性能调优之连接配置优化
  • 26岁备考PMP,经验分享
  • 支持selenium的chrome driver更新到132.0.6834.83
  • 嵌入式知识体系分析+数据结构概念+时间复杂度计算规则+顺序表的原理与实现
  • 论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(一)
  • DeepSeek-R1技术突破:基础模型强化学习+蒸馏小模型超越o1-mini