这是一个针对 CoreAnimation 变换(CATransform3D)的特定领域语言。
不再是像这样编写代码
CATransform3D *theTransform = CATransform3DScale(CATransform3DMakeTranslation(1, 2, 0), 10, 10, 1);
而是这样编写代码
#import "NIMTransformFormatter.h"
CATransform3D theTransform = CATransform3DMakeWithFormat(@"translate(1,2) | scale(10,10,1.0)");
甚至更短
CATransform3D theTransform = CATransform3DMakeWithFormat(@"t(1,2) | s(10,10,1.0)");
如果您有直接使用类的原因。
CATransform3D theTransform = [[NIMTransformFormatter formatterWithFormat:@"t(1,2) | s(10,10,1.0)"] CATransform3D];
最后,如果您要转换现有的 CATransform3D,可以使用这种形式(感谢 @ntakayama 的建议。)
someLayer.transform = CATransform3DWithFormat(someLayer.transform, @"t(1,2) | s(10,10,1.0)");
目前它在 Backus-Naur 形式下看起来是这样的(理论上)
<operation-name> ::= "translate" | "scale" | "rotate" | "identity"
<placeholder> ::= "%f"
<parameter> ::= <floating-point-number> | <placeholder>
<parameter-list> ::= <parameter> | <parameter-list> "," <parameter>
<operation> ::= <operation-name> "(" <parameter-list> ")"
<concat-operator> ::= "|"
<operation-list> ::= <operation> | <concat-operator> <operation-list>
(this is pretty incorrect BNF - dont rely on it yet)
要注意的关键部分是操作看起来有点像函数,并且使用 |(竖线)字符连接。
请注意,操作名称不区分大小写,并且可以缩短到仅第一个唯一的字符(例如,“t”对应于“translate”)。
这返回仅矩阵单位阵。您可能永远不会需要使用它
identity()
这返回一个按 X 和 Y 缩放 10.0,Z 缩放 1.0 的单位阵。
identity() | scale(10, 10, 1)
默认情况下隐含单位阵。因此,前面的格式等效于此格式。注意,如果传递自己的基础变换,则操作将相对于该变换。
scale(10, 10, 1)
我们可以推断 Z 缩放。缩放操作中的任何参数都推断为 1.0
scale(10, 10)
这是一个平移操作,沿 X 轴向下 100 像素
translate(-100, 0, 0)
但当然,我们可以推断其他两个轴
translate(-100)
让我们把这些组合起来
scale(10, 10) | translate(-100)
让我们再缩短一下
s(10,10) | t(-100)
显然您不会在每次变换时传递常数。因此,变换字符串首先经过 sprintf 格式化。这允许您编写类似以下代码
CATransform3D *theTransform = CATransform3DMakeWithFormat(@"translate(%f,%f) | scale(10,10,1.0)", X, Y);
使用多个嵌套函数创建复杂变换很痛苦。最终你会得到代码,难以快速更改,例如,如果需要重新排序变换操作或在某一选项之间添加另一个操作。
使用这种特定领域语言创建变换非常简单。操作不嵌套,因此您可以很容易地从左到右读取操作。您可以很容易地重新排序操作并在操作列表中插入操作。
这个函数的一个用途可能是如果你想将变换保存到数据中(比如你的plist文件或JSON文件)。以字符串形式表示变换会非常方便。要最大化其可用性,我们还需要支持将矩阵转换为字符串。请参阅“进一步的想法”部分。
这个领域特定语言(DSL)比手动执行操作要慢得多。
2014-03-20 18:20:21.168 TransformTest[59794:303] Time for non-parametized expression: 0.15035
2014-03-20 18:20:21.571 TransformTest[59794:303] Time for parametized expression: 0.400879
2014-03-20 18:20:21.574 TransformTest[59794:303] Time for raw CA function calls: 0.00237203
2014-03-20 18:20:21.574 TransformTest[59794:303] Slow-down factor for non-parametrized: 63.3846
2014-03-20 18:20:21.575 TransformTest[59794:303] Slow-down factor for parametrized: 169.003
Program ended with exit code: 0
这意味着使用不带参数的格式字符串大约比使用CA函数执行变换慢60倍。使用带参数的格式字符串则大约慢170倍。性能差异的原因是非参数化的表达式很容易被缓存 - 格式只解析一次。
这太慢了吗?这取决于你如何使用这些变换。如果你只是使用这些变换来计算动画的初始值和最终值,可能没问题。如果你自己进行动画并以此每秒60帧计算变换,可能就太慢了。
BSD 2条款,见LICENSE文件。