SwiftUIArkUI-曲线动画Path和路径动画motionPath

news2024/11/17 23:36:48

OpenHarmony Path ArkUI 高性能 motionPath 动效 三次贝塞尔曲线 曲线动画 SwiftUI

SwiftUI通过Path可以绘制路径动画,通过addCurve可用绘制三次贝塞尔曲线。

ArkUI是鸿蒙的核心UI布局框架,使用motionPath绘制路径动画,通过绘制路径可以自定义三次贝塞尔曲线。

对比分析

SwiftUIArkUI
PathmotionPath
The outline of a 2D shape.设置组件进行位移动画时的运动路径。
struct Path.motionPath({})
addCurve绘制路径
addCurve(to:control1:control2:)Mstart.x start.y C -200 50, -150 200, end.x end.y

在SwiftUI中,可用通过设置三个关键点(结束点、控制1、控制2)调整贝塞尔曲线。

mutating func addCurve(
    to end: CGPoint,
    control1: CGPoint,
    control2: CGPoint
)

在ArkUI中,贝塞尔曲线的参数是硬编码,字符串各个参数中间用空格隔开。

Button('click me').margin(50)
        // 执行动画:从起点移动到(300,200),再到(300,500),再到终点
        .motionPath({ path: 'Mstart.x start.y L300 200 L300 500 Lend.x end.y', from: 0.0, to: 1.0, rotatable: true })

硬编码容易出现拼写错误,参数不易理解问题。

SwiftUI通过Path应用实践

通过以下三个结构体可以完成一个简单的路径动画:

  1. 贝塞尔曲线动画
  2. 路径动画
  3. 构建视图

实践代码

贝塞尔曲线动画

struct InfinityShape2: Shape {
    func path(in rect: CGRect) -> Path {
        return InfinityShape2.createInfinityPath(in: rect)
    }

    static func createInfinityPath(in rect: CGRect) -> Path {
        let height = rect.size.height
        let width = rect.size.width
        let heightFactor = height/4
        let widthFactor = width/4

        var path = Path()
        
        path.move(to: CGPoint(x:widthFactor, y: heightFactor * 6))
        path.addCurve(to: CGPoint(x:widthFactor, y: heightFactor), control1: CGPoint(x:0, y: heightFactor * 6), control2: CGPoint(x:0, y: heightFactor))

        path.move(to: CGPoint(x:widthFactor, y: heightFactor))
        path.addCurve(to: CGPoint(x:widthFactor * 3, y: heightFactor * 3), control1: CGPoint(x:widthFactor * 2, y: heightFactor), control2: CGPoint(x:widthFactor * 2, y: heightFactor * 3))

        path.move(to: CGPoint(x:widthFactor * 3, y: heightFactor * 3))
        path.addCurve(to: CGPoint(x:widthFactor * 3, y: heightFactor), control1: CGPoint(x:widthFactor * 4 + 5, y: heightFactor * 3), control2: CGPoint(x:widthFactor * 4 + 5, y: heightFactor))

        path.move(to: CGPoint(x:widthFactor * 3, y: heightFactor))
        path.addCurve(to: CGPoint(x:widthFactor, y: heightFactor * 6), control1: CGPoint(x:widthFactor * 1, y: heightFactor), control2: CGPoint(x:widthFactor * 2, y: heightFactor * 6))
        
        return path
    }
}

路径动画

struct FollowEffect2: GeometryEffect {
    var pct: CGFloat = 0
    let path: Path
    var rotate = true

    var animatableData: CGFloat {
        get { return pct }
        set { pct = newValue }
    }

    func effectValue(size: CGSize) -> ProjectionTransform {

        if !rotate {
            let pt = percentPoint(pct)

            return ProjectionTransform(CGAffineTransform(translationX: pt.x, y: pt.y))
        } else {
            // Calculate rotation angle, by calculating an imaginary line between two points
            // in the path: the current position (1) and a point very close behind in the path (2).
            let pt1 = percentPoint(pct)
            let pt2 = percentPoint(pct - 0.01)

            let a = pt2.x - pt1.x
            let b = pt2.y - pt1.y

            let angle = a < 0 ? atan(Double(b / a)) : atan(Double(b / a)) - Double.pi

            let transform = CGAffineTransform(translationX: pt1.x, y: pt1.y).rotated(by: CGFloat(angle))

            return ProjectionTransform(transform)
        }
    }

    func percentPoint(_ percent: CGFloat) -> CGPoint {

        let pct = percent > 1 ? 0 : (percent < 0 ? 1 : percent)

        let f = pct > 0.999 ? CGFloat(1-0.001) : pct
        let t = pct > 0.999 ? CGFloat(1) : pct + 0.001
        let tp = path.trimmedPath(from: f, to: t)

        return CGPoint(x: tp.boundingRect.midX, y: tp.boundingRect.midY)
    }
}

最后,构建view

struct ExamplePlane: View {
    @State private var flag = false

    var body: some View {
        GeometryReader { proxy in
            ZStack(alignment: .topLeading) {
                
                // Draw the Infinity Shape
                InfinityShape2().stroke(Color.red, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .miter, miterLimit: 0, dash: [7, 7], dashPhase: 0))
                    .foregroundColor(.blue)
                    .frame(width: proxy.size.width, height: 300)

                // Animate movement of Image
                // Image(systemName: "airplane")
                Image(systemName: "airplane").resizable().foregroundColor(Color.red)
                    .frame(width: 80, height: 80).offset(x: -40, y: -40)
                    .modifier(FollowEffect2(pct: self.flag ? 1 : 0, path: InfinityShape2.createInfinityPath(in: CGRect(x: 0, y: 0, width: proxy.size.width, height: 300)), rotate: true))
                    .onAppear {
                        withAnimation(Animation.linear(duration: 4.0).repeatForever(autoreverses: false)) {
                            self.flag.toggle()
                        }
                    }

                }.frame(alignment: .topLeading)
        }
        .padding(20)
    }
}

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

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

相关文章

开箱即用版本 满分室间质评之GATK Somatic SNV+Indel+CNV+SV

最近准备为sliverworkspace 图形化生信平台开发报告设计器&#xff0c;需要一个较为复杂的pipeline作为测试数据&#xff0c;就想起来把之前的 满分室间质评之GATK Somatic SNVIndelCNVSV&#xff08;下&#xff09;性能优化翻出来用一下。跑了一遍发现还是各种问题&#xff0c…

想用iPhone录视频同时拍照片?这篇教你!附送10个苹果手机技巧

如果你在使用苹果手机录制视频时还想要拍摄静态照片&#xff0c;打开录制功能后&#xff0c;可以点击苹果手机屏幕右侧的白色圈圈&#xff0c;这时候&#xff0c;静态的照片就会自动保存到相册啦&#xff01; 哈哈&#xff0c;如果你想要反过来操作——用苹果手机拍照时顺便录…

对程序员来说,技术能力和业务逻辑哪个更重要?

一、前言 大家好&#xff0c;我是苍何。话说&#xff0c;小明和小华都是程序员&#xff0c;小明今年刚毕业在一家小金融公司实习&#xff0c;小华是工作了 8 年的 Java 开发&#xff0c;他们两最近都面临同样的问题「技术能力和业务逻辑哪个更重要&#xff1f;」&#xff0c;于…

【数据结构】手撕归并排序(含非递归)

目录 一&#xff0c;归并排序&#xff08;递归&#xff09; 1&#xff0c;基本思想 2&#xff0c;思路实现 二&#xff0c;归并排序&#xff08;非递归&#xff09; 1&#xff0c;思路实现 2&#xff0c;归并排序的特性总结&#xff1a; 一&#xff0c;归并排序&#xff0…

七、Thymeleaf对象的访问

7.1、实体对象属性的访问 使用变量表达式访问对象属性时&#xff0c;可以使用"对象.属性名"的语法。注意此处的属性名是对象属性getter方法的名称。 示例 在项目包下添加domain包&#xff0c;在包中创建“User”类&#xff0c;添加userId和userName属性 import jav…

极验文字点选验证

测试网址&#xff1a; 验证码验证形式展示-滑动图片验证-点选验证-极验交互安全极验GEETEST提供丰富多样的行为验证形式来应对网络攻击&#xff0c;如滑动拼图验证&#xff0c;智能无感验证&#xff0c;文字/图标/语序点选验证和空间推理验证等……这些验证形式在PC端和移动端…

跨境电商建站:选择域名需要注意什么?

在跨境电商建站过程中&#xff0c;选择一个合适的域名是至关重要的。本文将介绍域名和网址的区别&#xff0c;解释域名选择的重要性&#xff0c;并提供一些关于如何选择域名的建议。同时&#xff0c;还会涉及到老域名的优势和注意事项。内容并不复杂&#xff0c;希望对大家有所…

Java基于SpringBoot的车辆充电桩

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1、效果演示效果图 技术栈2、 前言介绍&#xff08;完整源码请私聊&#xff09;3、主要技术3.4.1…

面试题:在大型分布式系统中,给你一条 SQL,让你优化,你会怎么做?

亲爱的小伙伴们&#xff0c;大家好呀&#xff01;我是小米&#xff0c;一个热爱技术、乐于分享的90后程序猿。今天&#xff0c;我要和大家聊聊一个在大型分布式系统中非常有趣和挑战性的话题——如何优化 SQL 查询&#xff01; 这个问题可不简单&#xff0c;但不要担心&#x…

[发现了好东西] MS teams 使用-表情小窗口

在是有MS teams时&#xff0c;对话框里的每一条消息&#xff0c;当鼠标游离其上时&#xff0c;都会出现一个表情小窗口。其实这个小窗口非常的烦人&#xff0c;尤其是需要复制消息内容时。这个小窗口容易导致误操作&#xff0c;所以非常的非常烦人。 从微软的主页上搜&#xff…

昨天面试一个武大的,10年经验,薪资只要1万二!

昨天面试了一个武大的&#xff0c;10年经验&#xff0c;只要一万二&#xff0c;虽然是二线城市&#xff0c;但是这个学历和工作经验&#xff0c;我还是比较震惊的。 和他聊了一番&#xff0c;他回答地比较真诚&#xff0c;但是最后我不得不拒绝他。 首先他有大厂的经历。 我…

电容笔有必要买苹果原装的吗?ipad第三方电容笔了解下

在当今世界&#xff0c;高科技已经成为推动电子产品迅速发展的一股重要力量。无论是在工作上&#xff0c;还是在学习上&#xff0c;都很方便。iPad会和我们的生活联系在一起&#xff0c;不管是现在还是未来。iPad配上一支简单的电容笔&#xff0c;可以提高工作和学习的效率&…

springboot+jsp+ssm高校图书馆图书借阅收藏评论管理系统617w1

本图书管理系统系统采用B/S架构&#xff0c;数据库是MySQL&#xff0c;网站的搭建与开发采用了先进的Java进行编写&#xff0c;使用了SSM&#xff08;Spring、SpringMVC、Mybits&#xff09;框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。前台主要功…

Flexmonster Pivot Table 2.9.1 Crack

Flexmonster Pivot Table & Charts 2.9.X 是一个专门为实时可视化复杂业务数据而设计的组件。该实用程序是用JavaScript编写的&#xff0c;不需要额外的插件&#xff0c;也不受运行的服务器类型的限制。事实上&#xff0c;它的设计可以轻松地与当今大多数可用的开发框架集成…

拓世AI|中秋节营销攻略,创意文案和海报一键生成

秋风意境多诗情&#xff0c;中秋月圆思最浓。又是一年中秋节&#xff0c;作为中国传统的重要节日之一&#xff0c;中秋节的意义早已不再仅仅是一家团圆的节日&#xff0c;更是一场商业盛宴。品牌方们纷纷加入其中&#xff0c;希望能够借助这一节日为自己的产品赢得更多的关注和…

物流批量查询:一键查询全部物流信息,高效管理快递

你是否曾经为了查询快递信息而感到困扰&#xff1f;特别是当你需要查询多个快递单号时&#xff0c;重复的输入和查询不仅耗时&#xff0c;还容易出错。为了解决这个问题&#xff0c;我们找到了一个名为“固乔快递查询助手”的软件&#xff0c;它能够让你一次性查询所有需要的快…

报错处理:MySQL报错解决:连接失败原因与解决方案

大家好&#xff0c;今天我来分享一下在Linux上遇到的一个MySQL连接失败的报错以及解决方法。如果你在尝试连接MySQL数据库时遇到以下报错信息&#xff1a;“Can’t connect to MySQL server on ‘localhost’ (111)”&#xff0c;那么请接着往下看&#xff0c;我会帮你找到可能…

安卓 Android 终端接入阿里云 IoT 物联网平台

在全球智能手机市场里&#xff0c;谷歌开发的安卓(Android)移动操作系统市场占有率已经高达90%。随着物联网智能硬件升级&#xff0c;安卓(Android)也逐渐成为智能摄像头&#xff0c;智能对讲门禁&#xff0c;人脸识别闸机&#xff0c;智能电视&#xff0c;智能广告屏等带屏 Io…

Vulnhub_driftingblues1靶机渗透测试

driftingblues1靶机 信息收集 使用nmap扫描得到目标靶机ip为192.168.78.166&#xff0c;开放80和22端口 web渗透 访问目标网站&#xff0c;在查看网站源代码的时候发现了一条注释的base64加密字符串 对其解密得到了一个目录文件 访问文件发现是一串ook加密的字符串&#xf…

云原生监控系统Prometheus:基于Prometheus构建智能化监控告警系统

目录 一、理论 1.Promethues简介 2.监控告警系统设计思路 3.Prometheus监控体系 4.Prometheus时间序列数据 5.Prometheus的生态组件 6.Prometheus工作原理 7.Prometheus监控内容 8.部署Prometheus 9.部署Exporters 10.部署Grafana进行展示 二、实验 1.部署Prometh…