【发布时间】:2019-02-11 00:08:00
【问题描述】:
我在 Android 上开发了一个应用程序,您可以在其中在屏幕上添加图像并平移/旋转/缩放它们。从技术上讲,我有一个固定方面的父布局,其中包含这些图像(ImageViews)。他们已将宽度和高度设置为 match_parent。然后,我可以将他们的位置保存在服务器上,然后我可以稍后将其加载到同一设备或其他设备上。基本上,我只是保存 Matrix 值。但是,平移 x/y 具有绝对值(以像素为单位),但屏幕尺寸不同,因此我将它们设置为百分比值(因此平移 x 除以父宽度,平移 y 除以父高度)。加载图像时,我只需将平移 x/y 乘以父布局宽度/高度,即使在不同的设备上,一切看起来都一样。
我是这样做的:
float[] values = new float[9];
parentLayout.matrix.getValues(values);
values[Matrix.MTRANS_X] /= parentLayout.getWidth();
values[Matrix.MTRANS_Y] /= parentLayout.getHeight();
然后在加载函数中,我只是将这些值相乘。
图像操作是通过使用带有锚点的 postTranslate/postScale/postRotate 完成的(对于两指手势,它位于这些手指之间的中点)。
现在,我想将此应用程序移植到 iOS 并使用类似的技术在 iOS 设备上实现正确的图像位置。 CGAffineTransform 似乎与 Matrix 类非常相似。字段的顺序不同,但它们的工作方式似乎相同。
假设这个数组是来自 Android 应用的示例值数组:
let a: [CGFloat] = [0.35355338, -0.35355338, 0.44107446, 0.35355338, 0.35355338, 0.058058262]
我不保存最后 3 个字段,因为它们始终为 0、0 和 1,并且在 iOS 上它们甚至无法设置(文档还指出它是 [0, 0, 1])。所以这就是“转换”的样子:
let tx = a[2] * width //multiply percentage translation x with parent width
let ty = a[5] * height //multiply percentage translation y with parent height
let transform = CGAffineTransform(a: a[0], b: a[3], c: a[1], d: a[4], tx: tx, ty: ty)
但是,这只适用于非常简单的情况。对于其他人来说,图像通常是错位的,甚至是完全混乱的。
我注意到,默认情况下,在 Android 上我的锚点位于 [0, 0],但在 iOS 上它是图像的中心。
例如:
float midX = parentLayout.getWidth() / 2.0f;
float midY = parentLayout.getHeight() / 2.0f;
parentLayout.matrix.postScale(0.5f, 0.5f, midX, midY);
给出以下矩阵:
0.5, 0.0, 360.0,
0.0, 0.5, 240.0,
0.0, 0.0, 1.0
[360.0, 240.0] 只是一个从左上角开始的向量。
但是,在 iOS 上我不必提供中间点,因为它已经围绕中心进行了转换:
let transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
它给了我:
CGAffineTransform(a: 0.5, b: 0.0, c: 0.0, d: 0.5, tx: 0.0, ty: 0.0)
我尝试在 iOS 上设置不同的锚点:
parentView.layer.anchorPoint = CGPoint(x: 0, y: 0)
但是,我无法得到正确的结果。我尝试过按 -width * 0.5、-height * 0.5 进行翻译、缩放和翻译回来,但我没有得到与 Android 相同的结果。
简而言之:如何将 Matrix 从 Android 修改为 CGAffineTransform 从 iOS 以获得相同的外观?
我还附上了尽可能简单的演示项目。目标是将 Android 的输出数组复制到 iOS 项目中的“a”数组中,并修改 CGAffineTransform 计算(和/或 parentView 设置),以使图像在两个平台上看起来都相同,无论 Android 的日志输出是什么。
安卓: https://github.com/piotrros/MatrixAndroid
iOS: https://github.com/piotrros/MatrixIOS
编辑:
@Sulthan 解决方案效果很好!尽管如此,我想出了一个逆转过程的子问题,我也需要它。根据他的回答,我尝试将其整合到我的应用中:
let savedTransform = CGAffineTransform.identity
.concatenating(CGAffineTransform(translationX: -width / 2, y: -height / 2))
.concatenating(
self.transform
)
.concatenating(CGAffineTransform(translationX: width / 2, y: height / 2))
let tx = savedTransform.tx
let ty = savedTransform.ty
let t = CGAffineTransform(a: savedTransform.a, b: savedTransform.b, c: savedTransform.c, d: savedTransform.d, tx: tx / cWidth, ty: ty / cHeight)
placement.transform = [Float(t.a), Float(t.c), Float(t.tx), Float(t.b), Float(t.d), Float(t.ty), 0, 0, 1]
placement 只是一个保存“Android”版本矩阵的类。 cWidth / cHeight 是父级的宽度/高度。我将 tx/ty 除以它们以获得百分比宽度/高度,就像我在 Android 上所做的那样。
但是,它不起作用。 tx/ty 是错误的。
输入:
[0.2743883, -0.16761175, 0.43753636, 0.16761175, 0.2743883, 0.40431038, 0.0, 0.0, 1.0]
它回馈:
[0.2743883, -0.16761175, 0.18834576, 0.16761175, 0.2743883, 0.2182884, 0.0, 0.0, 1.0]
所以除了 tx/ty 以外的一切都很好。哪里出错了?
【问题讨论】:
-
如何将所有 layer.anchorpoint 更改为 x:0、y:0 或 x:0 y:1。我们知道这是关键问题。正确的产地可以为您节省大量工作。
-
是的,我知道。我认为这是一个简单的错误,但我找不到正确的设置。我已经尝试过 (x: 0, y: 0) 和 (x: 0, y: 1) 枢轴,但这是错误的。只需在演示项目上亲自尝试即可。
标签: ios swift core-graphics