分解 0.0.5

分解 0.0.5

Adam Bell维护。




分解 0.0.5

分解

Tests Docs

操作和使用CATransform3D进行动画和交互相当具有挑战性... 分解使CATransform3Dmatrix_double4x4matrix_float4x4更容易使用。

注意:分解的API仍在不断更改/优化,所以请随时提供反馈,并预料未来可能会有重大更改。

具体来说,我很想弄清楚如何处理在这个仓库中引入的Vector类型。如果有任何问题,请告诉我;我正在积极寻找使它变得更加完善的途径。

简介

通常在iOS上,如果你想转换一个CALayer,你会这样做

let layer: CAlayer = ...
layer.transform = CATransform3DMakeScale(0.5, 0.5, 1.0)

然而,如果你从一个别的地方得到了一个转换怎么办?你怎么知道层的缩放比例是多少?如果你想要设置转换的缩放或平移怎么办?没有复杂的线性代数,这并不容易做到!

Decomposed旨在通过允许对CATransform3Dmatrix_double4x4matrix_float4x4进行分解、重新组合和变异,从而简化这一点,而不需要复杂的数学。

分解是将某物分解成较小的组件的过程,在这种情况下是将转换矩阵分解成翻译、缩放等,这样它们可以单独更改或重置。以下是所支持的:

  • 平移
  • 缩放
  • 旋转(使用四元数或欧拉角)
  • 倾斜
  • 透视

它还由Accelerate支持,因此它在矩阵操作中应该引入相对较低的开销。

使用方法

API 文档在这里:here.

转换修改

Swift

创建一个沿Y轴平移44个点,以π/4.0沿X轴旋转的转换

var transform: CATransform3D = CATransform3DIdentity
  .translatedBy(y: 44.0)
  .rotatedBy(angle: .pi / 4.0, x: 1.0)

Objective-C

创建一个沿Y轴平移44个点,绕X轴旋转π/40的变换。

CATransform3DDecomposed *decomposed = [DEDecomposedCATransform3D decomposedTransformWithTransform:CATransform3DIdentity];
decomposed.translation = CGPoint(0.0, 44.0);
decomposed.rotation = simd_quaternion(M_PI / 4.0, simd_make_double3(1.0, 0.0, 0.0));
transform = [decomposed recompose];

CALayer 扩展

通常在使用 UIViewCALayer 进行交互式手势操作时,您在更改变换时需要处理隐式动作(动画)。 Decomposed 可以自动为您处理这个问题,而不需要在代码中封装 CATransactions 并禁用动作。

Swift

// In some UIPanGestureRecognizer handling method
layer.translation = panGestureRecognizer.translation(in: self)
layer.scale = CGPoint(x: 0.75, y: 0.75)

Objective-C

由于Objective-C中存在命名空间冲突,您可以通过`transformProxy`属性进行类似更改。对此代理对象所做的更改将应用于层变换,且启用了隐式动画。

// In some UIPanGestureRecognizer handling method
layer.transformProxy.translation = [panGestureRecognizer translationInView:self];
layer.transformProxy.scale = CGPoint(x: 0.75, y: 0.75);

分解变换

每次在CATransform3Dmatrix_double4x4上更改属性时,都需要进行分解、更改,然后再重新组合。这如果很频繁进行可能会很昂贵,因此应该限制其使用。如果您一次更改多个属性,最好是先更改分解变换,然后调用其重新组合函数以获取重新组合的变换。

Swift

var decomposed = transform.decomposed()
decomposed.translation = Translation(44.0, 44.0, 0.0)
decomposed.scale = Scale(0.75, 0.75, 0.0)
decomposed.rotation = CGQuaternion(angle: .pi / 4.0, axis: CGVector3(1.0, 0.0, 0.0))

let changedTransform = decomposed.recomposed()

Objective-C

DEDecomposedCATransform3D *decomposed = [DEDecomposedCATransform3D decomposedTransformWithTransform:transform];
decomposed.translation = CGPointMake(44.0, 44.0);
decomposed.scale = CGPointMake(0.75, 0.75);
decomposed.rotation = simd_quaternion(M_PI / 4.0, simd_make_double3(1.0, 0.0, 0.0));

CATransform3D changedTransform = [decomposed recomposed];

CGVector3 / CGVector4 / CGQuaternion

很遗憾,simd不支持存储CGFloat(即使它们是Double)。为了让这个库更容易使用(例如,不需要将所有内容都强制转换为双精度浮点数,使用Double(some CGFloat)),您可以找到CGVector3CGVector4CGQuaternion,分别封装了simd对应的类型:simd_double3simd_double4simd_quatd

《平移》,`缩放`等等都是类型别名(即CGVector3CGVector4),并且它们都遵循ArrayLiteralRepresentable协议,因此可以使用`Array`来初始化它们。

layer.translation = Translation(44.0, 44.0, 0.0)
layer.scale = Scale(0.5, 0.75, 0.0)

注意:当前这种形式的API存在疑问,因为它与Swift的`Vector`类型(只是 simd 类型,我认为所有内容都应公开为`simd`类型)冲突,所以我欢迎您提供反馈!

可插值

此外,它还通过可插值协议提供了从任何转换到任何转换的线性插值功能。这使得您能够以受控的方式轻松地动画化/过渡到转换之间。

let transform: CATransform3D = CATransform3DIdentity
  .translatedBy(x: 44.0, y: 44.0)

let transform2 = CATransform3DIdentity
  .translatedBy(x: 120.0, y: 240.0)
  .scaled(by: [0.5, 0.75, 1.0])
  .rotatedBy(angle: .pi / 4.0, x: 1.0)

let interpolatedTransform = transform.lerp(to: transform2, fraction: 0.5)

安装

要求

  • iOS 13+、macOS 10.15+
  • Swift 5.0 或更高版本

目前Decomposed支持Swift Package Manager、CocoaPods、Carthage,以及作为Xcode子项目手动使用。欢迎为其他依赖系统/构建系统提交拉取请求!

Swift 包管理器

将以下内容添加到您的 Package.swift 文件中(或者通过 Xcode 的 GUI 添加)

.package(url: "https://github.com/b3ll/Decomposed", from: "0.0.1")

CocoaPods

将以下内容添加到您的 Podfile

pod 'Decomposed'

注释

由于某种原因,当使用CocoaPods和本库的Objective-C部分时,您可能会看到以下错误

声明'DEDecomposedCATransform3D'必须在使用前从模块'Decomposed.Swift'导入.

要修复此问题,您需要使用Objective-C++文件(即将文件名从.m更改为.mm)或更改导入如下

#import <Decomposed/Decomposed.h>
#import <Decomposed/Decomposed-Swift.h>

目前我没有任何其他解决方案,如果将来有,我会进行更新。

Carthage

将以下内容添加到您的 Cartfile

"b3ll/Decomposed"

Xcode 子项目

  • Decomposed.xcodeproj 添加到您的项目中
  • Decomposed.framework 添加为嵌入式框架(它是一个静态库,因此不应嵌入式)。

Objective-C 笔记

  • Objective-C 支持通过 Swift 包管理器不可用。请使用手动 Xcode 子项目。
  • 您需要使用 #import <Decomposed/Decomposed.h>,因为这个文件包含 Objective-C 类的生成的 Swift 接口和 CALayer 分类。
  • 由于 Swift / Objective-C 互操作性限制,并非所有 API 都可用。遗憾的是,API 的实现可能不会那么优雅,但是 CATransform3DDecomposed 允许对 CATransform3D 进行分解和重新组合(类似的类也存在于 matrix_double4x4matrix_float4x4 中,并且是它们的 Swift 对应包装器)以及 CALayer 上的便利分类。

其他推荐

高级

此库与iOS基于物理动画系统的高级(a physics-based animation system for iOS)配合得非常好。

通过修改层上的变换来在弹簧上动画是一个层,这从未如此简单!通常,您必须手动将事物包装在禁用动作的CATransaction中,而使用CATransform3DTranslate变得相当繁琐。

使用分解+高级,这变得超级简单。

let layer = ...
let spring = Spring<CGPoint>(initialValue: .zero)
spring.onChange = { [layer] translation in
  layer.translation = translation
}

// In your pan gesture recognizer callback

let translation = panGestureRecognizer.translation(in: self.view)
let velocity = panGestureRecognizer.velocity(in: self.view)

switch panGestureRecognizer.state {
  case .began:
    spring.reset(to: .zero)
    break
  case .changed:
    layer.translation = translation
    break
  case .ended:
    spring.velocity = velocity
    spring.target = CGPoint(x: 200.0, y: 200.0) // wherever you want it to go
    break
}

查看DraggingCard示例,了解如何使用此功能 :)

许可证

Decomposed 采用 BSD 2-clause 许可证 许可。

联系方式

欢迎在推特上关注我:[b3ll](https://www.twitter.com/b3ll)!