Date
Nov. 21st, 2024
 
2024年 10月 21日

Post: iOS Animation : 拖拽气泡的基本算法

iOS Animation : 拖拽气泡的基本算法

Published 12:10 Oct 13, 2015.

Created by @ezra. Categorized in #Programming, and tagged as #iOS.

Source format: Markdown

Table of Content

通过前面博客的介绍,你应该已经对 UIBezierPath 的基本使用有了了解,接下来,本文主要介绍 UIBezierPath 在 UI 动画中的应用——拖拽气泡的基本算法。

初步构想

首先来分析拖拽气泡的结构:

效果

如上图,气泡初始状态为正圆形,拖拽后,左右两端分别为两个大小不同的正圆,由两条曲线连接,其内部填充为统一的颜色,也就是说我们只需要绘制两个圆弧,两条长曲线,拼接为完整的路径并进行填充即可。

计算公式

有了上面的分析,我们初步构想了气泡的原理,接下来就需要对其中的数值进行精确的计算,得到通用的计算公式。

计算

如图, AE ⊥ ABBF ⊥ ABAE = BF = distance / 2,如果用 distance 表示两圆圆心间距离,则:

  • distance = √((x1 - x2)² + (y1 - y2)²)

  • cosα = (y2 - y1) / distance

  • sinα = (x2 - x1) / distance

据此,我们可以进一步得到 ABCD 四个点的坐标:

  • A: (x1 - r1 * cosα, y1 + r1 * sinα)

  • B: (x1 + r1 * cosα, y1 - r1 * sinα)

  • C: (x2 + r2 * cosα, y2 - r2 * sinα)

  • D: (x2 - r2 * cosα, y2 + r2 * sinα)

如果用 (xA, yA) 表示 A 点坐标,同理用用 (xB, yB) 表示 B 点坐标,则 EF 两点坐标为:

  • E: (xA + distance / 2 * sinα, yA + distance / 2 * cosα)

  • F: (xB + distance / 2 * sinα, yB + distance / 2 * cosα)

代码实现

接下来,有了前面的计算公式,我们将用代码去实现,首先创建相关值变量:

var r1: CGFloat!
var x1: CGFloat!
var y1: CGFloat!

var r2: CGFloat!
var x2: CGFloat!
var y2: CGFloat!

var centresDistance: CGFloat!
var cosAlpha: CGFloat!
var sinAlpha: CGFloat!

var pointA: CGPoint!
var pointB: CGPoint!
var pointD: CGPoint!
var pointC: CGPoint!
var pointE: CGPoint!
var pointF: CGPoint!

接下来,实现 ABCDEF 点的坐标计算:

func calcutePoints() {
    // 圆心距离
    let num = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
    centresDistance = CGFloat(sqrt(num))

    // sinα 和 cosα
    if centresDistance == 0 {
        cosAlpha = 1;
        sinAlpha = 0;
    } else {
        cosAlpha = (y2 - y1) / centresDistance;
        sinAlpha = (x2 - x1) / centresDistance;
    }

    pointA = CGPointMake(x1 - r1 * cosAlpha, y1 + r1 * sinAlpha);
    pointB = CGPointMake(x1 + r1 * cosAlpha, y1 - r1 * sinAlpha);
    pointC = CGPointMake(x2 + r2 * cosAlpha, y2 - r2 * sinAlpha);
    pointD = CGPointMake(x2 - r2 * cosAlpha, y2 + r2 * sinAlpha);
    pointE = CGPointMake(pointA.x + (centresDistance / 2)*sinAlpha, pointA.y + (centresDistance / 2) * cosAlpha);
    pointF = CGPointMake(pointB.x + (centresDistance / 2)*sinAlpha, pointB.y + (centresDistance / 2) * cosAlpha);
}
Pinned Message
HOTODOGO
The Founder and CEO of Infeca Technology.
Developer, Designer, Blogger.
Big fan of Apple, Love of colour.
Feel free to contact me.
反曲点科技创始人和首席执行官。
开发、设计与写作皆为所长。
热爱苹果、钟情色彩。
随时恭候 垂询