iOS 17 测试版中 SwiftUI 视图首次显示时状态的改变导致动画“副作用”的解决方法

news2024/12/28 19:25:07

在这里插入图片描述

问题现象

精彩的 SwiftUI 动画可以让我们的 App 活灵活现、精妙绝伦。不过原本正常的动画在测试版本的 iOS 里却有着让码农持续秃头的“副作用”:

在这里插入图片描述

我们希望在视图首次显示时驱动状态改变来产生橘色小球围绕红球旋转的动画,红球应该始终保持在屏幕中心。

可是从上图中可以看到,红色大球本身也发生了斜线移动。

该问题目前只存在于 iOS 17 (beta 4)测试版中,iOS 16.x 里一切正常。

这是什么原因?又该如何解决呢?

文章目录

  • 问题现象
  • 1. 动画“副作用”的原因
  • 2. 一种不妥当的解决方法
  • 3. 绝薪止火:正确的解决之道
  • 总结

无需等待,Let‘s fix it!😉


1. 动画“副作用”的原因

首先,我们需要看一下源代码:

struct Planet: View {
    var angle: Angle
    let track_rect_side: CGFloat = 100.0
    
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 50, height: 50)
            
            Circle()
                .stroke(Color.gray, lineWidth: 1.0)
                .frame(width: track_rect_side, height: track_rect_side)
            
            Circle()
                .fill(.orange)
                .frame(width: 25, height: 25)
                .offset(x: track_rect_side/2.0 * cos(angle.radians), y: track_rect_side/2.0 * sin(angle.radians))
        }
        
    }
}

extension Planet: Animatable {
    var animatableData: Angle.AnimatableData {
        get { angle.animatableData }
        set { angle.animatableData = newValue }
    }
}

struct ContentView: View {
    @State var angle = Angle.zero
        
    var body: some View {
        NavigationStack {
            VStack {                
                Planet(angle: angle)
                    .animation(.linear(duration: 3.0).repeatForever(autoreverses: false), value: angle)
                    .onAppear {
                        angle = .degrees(360)
                    }
            }
            .frame(maxHeight: .infinity)
            .navigationTitle("带“副作用”的动画")
            .ignoresSafeArea()
        }
    }
}

上面的代码让 Planet 视图遵守 Animatable 动画协议来实现小球绕圈的自定义动画效果。


想进一步了解 SwiftUI 自定义动画的小伙伴们,请移步如下链接观赏更详细的内容:

  • SwiftUI 动画进阶:实现行星绕圆周轨道运动
  • SwiftUI 如何在动画完成时得到通知

从代码中可以看到,Planet 视图中 angle 状态的改变只会影响橘色小球的位置,为什么红色大球也会发生位移呢?

这疑似是 iOS 17 beta4(SwiftUI 5.0)测试版中的一个 Bug,因为从代码里看 angle 不会影响到 Planet 中的其它视图,更不会影响 Planet 自身。

而且在 iOS 16.4 (模拟器)和 iOS 16.6 (真机)中相同的代码都没有任何题!

那么,如何在 iOS 17 测试版中临时规避该问题呢?

2. 一种不妥当的解决方法

一种很简单但不怎么可靠的方法是:延时!

struct ContentView: View {
    @State var angle = Angle.zero
        
    var body: some View {
        NavigationStack {
            VStack {                
                Planet(angle: angle)
                    .animation(.linear(duration: 3.0).repeatForever(autoreverses: false), value: angle)
                    .onAppear {
                        // 略微延时以确保 Planet 处在屏幕中心!
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                            angle = .degrees(360)
                        }
                    }
            }
            .frame(maxHeight: .infinity)
            .navigationTitle("带“副作用”的动画")
            .ignoresSafeArea()
        }
    }
}

如上代码所示,我们希望用延时来确保状态改变时 Planet 已位于屏幕中心。

不过,如果主视图有多重动画加持或主线程负载较大时,无法保证 Planet 视图会在特定延时后完成屏幕位置上的渲染(Render)。

一句话:延时可能时灵时不灵!

3. 绝薪止火:正确的解决之道

正确的解决方法是:在 Planet 的根视图中关闭“动画”:

struct Planet: View {
    var angle: Angle
    let track_rect_side: CGFloat = 100.0
    
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 50, height: 50)
            
            Circle()
                .stroke(Color.gray, lineWidth: 1.0)
                .frame(width: track_rect_side, height: track_rect_side)
            
            Circle()
                .fill(.orange)
                .frame(width: 25, height: 25)
                .offset(x: track_rect_side/2.0 * cos(angle.radians), y: track_rect_side/2.0 * sin(angle.radians))
        }
        // 在 Planet 根视图上“关闭动画”,这并不影响其内部的动画效果。
        .animation(.none)
    }
}

不过, animation(_😃 方法已废弃,不再推荐使用:

在这里插入图片描述

别急,我们还有另一种类似的方法:

struct Planet: View {
    var angle: Angle
    let track_rect_side: CGFloat = 100.0
    
    var body: some View {
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 50, height: 50)
            
            Circle()
                .stroke(Color.gray, lineWidth: 1.0)
                .frame(width: track_rect_side, height: track_rect_side)
            
            Circle()
                .fill(.orange)
                .frame(width: 25, height: 25)
                .offset(x: track_rect_side/2.0 * cos(angle.radians), y: track_rect_side/2.0 * sin(angle.radians))
        }
        .transaction { transaction in
            transaction.animation = .none
        }
    }
}

如上代码所示:我们利用 SwiftUI 动画实际都由 Transaction 承载这一原理,将 Planet 根视图上 Transaction 对应的动画设为“空”,同样解决了问题。

最后要说明的是,如果该问题是 iOS 17(SwiftUI 5.0)测试版中的 Bug,那么它将很可能会在 iOS 17 的后续版本中被修复,让我们拭目以待!

总结

在本篇博文中,我们在 iOS 17 beta 4(SwiftUI 5.0)测试版中发现了 SwiftUI 视图首次显示时状态的改变会导致动画“副作用”的问题,并提出多种解决方案。

感谢观赏,再会!😎

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

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

相关文章

Flink的Standalone部署实战

在Flink是通用的框架,以混合和匹配的方式支持部署不同场景,而Standalone单机部署方便快速部署,记录本地部署过程,方便备查。 环境要求 1)JDK1.8及以上 2)flink-1.14.3 3)CentOS7 Flink相关信…

腾讯24届校招内推

校招开始啦~有兴趣的话可以扫我的码投,也可以分享给身边找工作的同学~ ❤投递攻略 1️⃣腾讯校招步骤,先微信扫码绑定内推关系,后在电脑上上传更改简历和部门投递 2️⃣投递时将选择投递部门,投递后将在…

实战项目-在线学院 阿里云视频的操作

一 阿里云视频 1.1 阿里视频上传 1.2 阿里云视频上传

Vue3 Vuex状态管理多组件传递数据简单应用

去官网学习→安装 | Vuex cd 项目 安装 Vuex&#xff1a; npm install --save vuex 或着 创建项目时勾选Vuex vue create vue-demo ? Please pick a preset: Manually select features ? Check the features needed for your project: (Press <space> to se…

RocketMQ主题下的队列只有两个被订阅

一、场景 主题下的队列只有两个被订阅 二、消费者 一共有两个消费者 Consumer1 所在消费组&#xff1a;C_TEST_1订阅主题&#xff1a;fsc_wb_ccs_web_orderly_84 Consumer2 所在消费组&#xff1a;C_TEST_1订阅主题&#xff1a;fsc_wb_ccs_web_84 三、原因 两个不同的消…

预演攻击:谁需要网络靶场,何时需要

"网络演习 "和 "网络靶场 "几乎是当今信息安全领域最流行的词汇。与专业术语不同的是&#xff0c;这些词对于企业和高级管理人员来说早已耳熟能详&#xff1a;法律要求他们进行演习&#xff0c;包括网络演习&#xff0c;而网络射击场也经常在企业界和媒体上…

数据生成 | MATLAB实现WGAN生成对抗网络数据生成

数据生成 | MATLAB实现WGAN生成对抗网络数据生成 目录 数据生成 | MATLAB实现WGAN生成对抗网络数据生成生成效果基本描述程序设计参考资料 生成效果 基本描述 1.WGAN生成对抗网络&#xff0c;数据生成&#xff0c;样本生成程序&#xff0c;MATLAB程序&#xff1b; 2.适用于MATL…

美能达打印机刷卡扫描文件后,用户收不到扫描邮件

环境: 柯尼卡美能达一体机 bizhub 287 域服务器 Windows server 2019 问题描述: 新员工在域服务器创建账户后同步到打印服务器上面,他们在打印机扫描文件后,自动发邮件那个邮箱上没有他们邮件,导致他们也收不到邮件 正常是用户在打印机上刷卡后扫描件文件为PDF格式,…

Jmeter 连接 MySQL 数据库脚本

1、创建线程组 2、创建 JDBC Connection Configuration 3、创建 JDBC Request 4、最终创建的目录 5、重点来了 5.1 在百度中下载个 MySQL-connector-Java-8.0.28.jar&#xff0c;放在 jmeter 的 bin 目录下 5.2 在测试计划中&#xff0c;将 jar 包添加到脚本中 5.3 输入参…

您可以购买 Banana Pi BPI-CM2 而不是 Raspberry Pi CM4。它提供什么?

最近&#xff0c;Banana Pi&#xff08;SINOVOIP&#xff09;推出了Banana Pi BPI-CM2系统级模块&#xff08;SoM&#xff09;。BPI-CM2 是类似于Raspberry Pi CM4 的计算模块&#xff0c;提供一系列令人印象深刻的功能。Banana BPI-CM2 SoM 采用Rockchip RK3568四核 Cortex-A5…

MMdetection在VisDrone2019上训练FCOS和CenterNet

配置环境 Python 3.5>PyTorch 1.1>CUDA 9.0NCCL 2>GCC 4.9mmcv‘’ 把mmdetection的代码下载下来 git clone https://github.com/open-mmlab/mmdetection.git进入这个mmdetection文件,准备编译mmdetection的文件 cd mmdetection 装一下下面这些包&#xff0c; #…

Three.js--》✨ 阳 光 dua 郎 大 男 孩 ✨——阿伟的自述

不要让鲲流太嚣张&#xff0c;我们杰流才是最弔的 ———— 阳光dua郎大男孩 目录 项目搭建 初始化three.js基础代码 获取项目所需素材 加载图片语音模型 今天简单实现一个three.js的3D故事小游戏&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能…

YOLOv5基础知识入门(7)— NMS(非极大值抑制)原理解析

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。NMS是指非极大值抑制&#xff08;non maximum suppression&#xff09;&#xff0c;它是一种常用于物体检测任务的算法。在物体检测中&#xff0c;通常会有多个预测框&#xff08;bounding box&#xff09;被提议出来&…

3D图像驱动live2d--Kalidokit--人脸动作捕捉

3D图像驱动live2d–Kalidokit 可在线实时根据摄像头中人脸动作实现动作捕捉 Kalidokit https://kit.kalidoface.com/live2d/ https://github.com/yeemachine/kalidokit

Spring系列篇--关于AOP【面向切面】的详解

目录 一.AOP是什么 二.案例演示 1.前置通知1.1 先准备接口 1.2然后再准备好实现类 1.3对我们的目标对象进行JavaBean配置 1.4 编写前置系统日志通知 1.5配置系统通知XML中的JavaBean 1.6 配置代理XML中的JavaBean 1.7 测试代码开始测试 注意这里有一个报错问题&…

谷歌在Chrome浏览器中推进抗量子加密技术

近日&#xff0c;Chromium博客上发表的一篇博文称&#xff0c;为了加强网络安全&#xff0c;应对迫在眉睫的量子计算机威胁&#xff0c;谷歌各个团队密切合作&#xff0c;为网络向抗量子密码学的过渡做好准备。 谷歌的Chrome团队在博客中写道&#xff0c;该项目涉及修订技术标准…

python3实现线性规划求解

Background 对于数学规划问题&#xff0c;有很多的实现。MatlabYALMIPCPLEX这个组合应该是比较主流的&#xff0c;尤其是在电力相关系统中占据着比较重要的地位。MATLAB是一个强大的数值计算工具&#xff0c;用于数学建模、算法开发和数据分析。Yalmip是一个MATLAB工具箱&#…

VS2022 CMake报错解决小结

目录 一、问题背景 二、问题分析 三、问题解决 一、问题背景 VS2022中能够跨平台的工程类型就是CMake项目&#xff0c;一套代码能跨windows/Linux/Mac多种操作系统。而实际使用时&#xff0c;发现相关资料比较少&#xff0c;需要摸索一下。 碰到的问题简述&#xff1a; 1、C…

VMware虚拟机Ubuntu无法连接网络的解决方法

一、解决办法 网络适配器设置 终端依次执行下面命令即可 sudo nmcli networking off sudo nmcli networking onsudo service network-manager start #或者 sudo service NetworkManager start成功出现这个图标&#xff0c;即代表网络连接成功。

Ubuntu中安装OpenSSL

文章目录 一、前期准备1.1 压缩包下载1.2 gcc, make等的安装二、安装配置 一、前期准备 1.1 压缩包下载 在安装openssl之前&#xff0c;我们需要下载对应的压缩包 https://www.openssl.org/source/openssl-3.0.1.tar.gz 此压缩包可以选择win上下载后解压再复制到本地虚拟机中…