如何围绕对角线旋转 CALayer?

2023-12-29

我正在尝试实现一个翻转动画,用于像 iPhone 应用程序这样的棋盘游戏。动画应该看起来像一个旋转并改变其背面颜色的游戏片段(有点像黑白棋棋子 http://en.wikipedia.org/wiki/Reversi)。我已经成功创建了一个围绕其正交轴翻转该片段的动画,但是当我尝试通过更改围绕 z 轴的旋转来围绕对角轴翻转它时,实际图像也会旋转(毫不奇怪)。相反,我想“按原样”绕对角轴旋转图像。

我尝试过改变layer.sublayerTransform但没有成功。

这是我当前的实现。它通过一个技巧来解决在动画结束时获得镜像图像的问题。解决方案是实际上不将图层旋转 180 度,而是将其旋转 90 度,更改图像,然后将其旋转回来。

最终版本:根据 Lorenzos 建议创建离散键控动画并计算每一帧的变换矩阵。此版本尝试根据图层大小估计所需的“引导”帧数量,然后使用线性键控动画。此版本以任意角度旋转,因此要绕对角线旋转,请使用 45 度角。

用法示例:

[someclass flipLayer:layer image:image angle:M_PI/4]

执行:

- (void)animationDidStop:(CAAnimationGroup *)animation
                finished:(BOOL)finished {
  CALayer *layer = [animation valueForKey:@"layer"];

  if([[animation valueForKey:@"name"] isEqual:@"fadeAnimation"]) {
    /* code for another animation */
  } else if([[animation valueForKey:@"name"] isEqual:@"flipAnimation"]) {
    layer.contents = [animation valueForKey:@"image"];
  }

  [layer removeAllAnimations];
}

- (void)flipLayer:(CALayer *)layer
            image:(CGImageRef)image
            angle:(float)angle {
  const float duration = 0.5f;

  CAKeyframeAnimation *rotate = [CAKeyframeAnimation
                                 animationWithKeyPath:@"transform"];
  NSMutableArray *values = [[[NSMutableArray alloc] init] autorelease];
  NSMutableArray *times = [[[NSMutableArray alloc] init] autorelease];
  /* bigger layers need more "guiding" values */
  int frames = MAX(layer.bounds.size.width, layer.bounds.size.height) / 2;
  int i;
  for (i = 0; i < frames; i++) {
    /* create a scale value going from 1.0 to 0.1 to 1.0 */
    float scale = MAX(fabs((float)(frames-i*2)/(frames - 1)), 0.1);

    CGAffineTransform t1, t2, t3;
    t1 = CGAffineTransformMakeRotation(angle);
    t2 = CGAffineTransformScale(t1, scale, 1.0f);
    t3 = CGAffineTransformRotate(t2, -angle);
    CATransform3D trans = CATransform3DMakeAffineTransform(t3);

    [values addObject:[NSValue valueWithCATransform3D:trans]];
    [times addObject:[NSNumber numberWithFloat:(float)i/(frames - 1)]];
  }
  rotate.values = values;
  rotate.keyTimes = times;
  rotate.duration = duration;
  rotate.calculationMode = kCAAnimationLinear;

  CAKeyframeAnimation *replace = [CAKeyframeAnimation
                                  animationWithKeyPath:@"contents"];
  replace.duration = duration / 2;
  replace.beginTime = duration / 2;
  replace.values = [NSArray arrayWithObjects:(id)image, nil];
  replace.keyTimes = [NSArray arrayWithObjects:
                      [NSNumber numberWithDouble:0.0f], nil];
  replace.calculationMode = kCAAnimationDiscrete;

  CAAnimationGroup *group = [CAAnimationGroup animation];
  group.duration = duration;
  group.timingFunction = [CAMediaTimingFunction
                          functionWithName:kCAMediaTimingFunctionLinear];
  group.animations = [NSArray arrayWithObjects:rotate, replace, nil];
  group.delegate = self;
  group.removedOnCompletion = NO;
  group.fillMode = kCAFillModeForwards;
  [group setValue:@"flipAnimation" forKey:@"name"];
  [group setValue:layer forKey:@"layer"];
  [group setValue:(id)image forKey:@"image"];

  [layer addAnimation:group forKey:nil];
}

原始代码:

+ (void)flipLayer:(CALayer *)layer
          toImage:(CGImageRef)image
        withAngle:(double)angle {
  const float duration = 0.5f;

  CAKeyframeAnimation *diag = [CAKeyframeAnimation
                               animationWithKeyPath:@"transform.rotation.z"];
  diag.duration = duration;
  diag.values = [NSArray arrayWithObjects:
                 [NSNumber numberWithDouble:angle],
                 [NSNumber numberWithDouble:0.0f],
                 nil];
  diag.keyTimes = [NSArray arrayWithObjects:
                   [NSNumber numberWithDouble:0.0f],
                   [NSNumber numberWithDouble:1.0f],
                   nil];
  diag.calculationMode = kCAAnimationDiscrete;

  CAKeyframeAnimation *flip = [CAKeyframeAnimation
                               animationWithKeyPath:@"transform.rotation.y"];
  flip.duration = duration;
  flip.values = [NSArray arrayWithObjects:
                 [NSNumber numberWithDouble:0.0f],
                 [NSNumber numberWithDouble:M_PI / 2],
                 [NSNumber numberWithDouble:0.0f],
                 nil];
  flip.keyTimes = [NSArray arrayWithObjects:
                   [NSNumber numberWithDouble:0.0f],
                   [NSNumber numberWithDouble:0.5f],
                   [NSNumber numberWithDouble:1.0f],
                   nil];
  flip.calculationMode = kCAAnimationLinear;

  CAKeyframeAnimation *replace = [CAKeyframeAnimation
                                  animationWithKeyPath:@"contents"];
  replace.duration = duration / 2;
  replace.beginTime = duration / 2;
  replace.values = [NSArray arrayWithObjects:(id)image, nil];
  replace.keyTimes = [NSArray arrayWithObjects:
                      [NSNumber numberWithDouble:0.0f], nil];
  replace.calculationMode = kCAAnimationDiscrete;

  CAAnimationGroup *group = [CAAnimationGroup animation];
  group.removedOnCompletion = NO;
  group.duration = duration;
  group.timingFunction = [CAMediaTimingFunction
                          functionWithName:kCAMediaTimingFunctionLinear];
  group.animations = [NSArray arrayWithObjects:diag, flip, replace, nil];
  group.fillMode = kCAFillModeForwards;

  [layer addAnimation:group forKey:nil];
}

你可以这样伪造:创建一个仿射变换,沿着对角线折叠图层:

A-----B           B
|     |          /
|     |   ->   A&D
|     |        /
C-----D       C

更改图像,并将 CALayer 转换回另一个动画。 这将产生图层绕其对角线旋转的错觉。

如果我没记错的话,矩阵应该是:

0.5 0.5 0
0.5 0.5 0
0   0   1

更新: 好吧,CAT 并不真的喜欢使用简并变换,但你可以这样近似:

CGAffineTransform t1 = CGAffineTransformMakeRotation(M_PI/4.0f);
CGAffineTransform t2 = CGAffineTransformScale(t1, 0.001f, 1.0f);
CGAffineTransform t3 = CGAffineTransformRotate(t2,-M_PI/4.0f);  

在我对模拟器的测试中,仍然存在问题,因为旋转发生的速度比平移快,因此对于纯黑色方块,效果有点奇怪。我想如果你有一个居中的精灵,周围有透明区域,那么效果将接近预期。然后您可以调整t3矩阵,看看是否能得到更有吸引力的结果。

经过更多研究,似乎应该通过关键帧为其自己的过渡设置动画,以获得对过渡本身的最大控制。假设你要在一秒钟内显示这个动画,你应该让十个矩阵每隔十分之一秒显示一次,而不使用 kCAAnimationDiscrete 进行插值;这些矩阵可以通过以下代码生成:

CGAffineTransform t1 = CGAffineTransformMakeRotation(M_PI/4.0f);
CGAffineTransform t2 = CGAffineTransformScale(t1, animationStepValue, 1.0f);
CGAffineTransform t3 = CGAffineTransformRotate(t2,-M_PI/4.0f);  

其中每个关键帧的animationStep值取自此进程:

{1 0.7 0.5 0.3 0.1 0.3 0.5 0.7 1}

也就是说:您将生成十个不同的变换矩阵(实际上是 9 个),将它们作为关键帧推送到每隔十分之一秒显示一次,然后使用“不插值”参数。您可以调整动画数量以平衡平滑度和性能*

*很抱歉可能出现错误,最后一部分是在没有拼写检查的情况下编写的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何围绕对角线旋转 CALayer? 的相关文章

  • SDK 和 iOS 部署目标。

    我使用最新的 SDK 4 1 构建项目并设置 iOS 部署目标 3 0 如果我使用4 0 sdk的某些方法 我可以在真正的iPhone 3 0上运行我的项目吗 您只能在 OS 3 设备上运行您的项目 如果有条件地编码围绕您想要使用的 OS
  • 使用ios sdk在youtube上上传视频的方法[重复]

    这个问题在这里已经有答案了 可能的重复 如何从 iOS 应用程序中将视频上传到 YouTube https stackoverflow com questions 3528568 how do i upload a video to you
  • 如何安全地重命名 iOS 分发配置文件?

    我几个小时前刚刚提交了我的第一个应用程序 现在处于 等待审核 状态 但我犯了一个错误 我已经命名了我的分配配置文件My Company Distribution Profile 我应该做的事情被命名为我的发行版配置文件My GAME Dis
  • 如何打开/关闭 iPhone 相机闪光灯 swift 2?

    我正在寻找如何打开 关闭 iPhone 的相机闪光灯 我发现了这个 IBAction func didTouchFlashButton sender AnyObject let avDevice AVCaptureDevice defaul
  • Xcode 6 Save for Enterprise Deployment 不再为 ipa 创建 plist?

    Xcode 5 帮助为企业 ipa 创建 plist 描述符 Xcode 6 6A313 仅创建 ipa 这是错误还是有意更改 如果是这样 退后一步的原因是什么 如果我之前没有使用 Xcode 5 生成 plist 我需要自己手动构建它 您
  • Brush 属性的 WPF ColorAnimation

    我想知道是否有人可以帮助我 我有一个标签 当在后面的代码中调用方法时 我需要能够在任意两种颜色之间交叉淡入淡出 迄今为止我最好的尝试 Private OldColor as Color Colors White Sub SetPulseCo
  • iPhone触摸形状或原始数据

    有人知道是否可以检测触摸形状吗 也许通过获取原始触摸屏数据 我在这里找到了这个问题 答案 如何获取原始触摸屏数据 https stackoverflow com questions 789737 iphone raw touchscreen
  • 我可以在滚动时固定表格的 tableHeaderView 位置吗?

    我有一个表视图 并在其 tableHeaderView 上附加了一个 UISegmentedControl 如何使 tableHeaderView 固定 以便即使在滚动表视图时也始终可以在同一位置查看 UISegmentedControl
  • 关闭子级后,父级 UIViewController 方向不应更改

    假设我有三个 UI 控制器 A B C A 是我的根控制器 在 ShouldAutoRotate 方法中我返回 YES 我从A到B呈现ModalView B gt 在ShouldAutoRotate方法中我返回Portrait 然后从B我向
  • iphone:使用 iOS 5 和 Xcode 4.2 提交应用程序? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我有一个在
  • UIView 子类中使用的 CAShapeLayer 不起作用

    我尝试了几个小时 用 CAShapeLayer 在 UIView 周围获得虚线边框 但我没有显示它 ScaleOverlay h import
  • iPhone 中的 UIGlassButton

    有人使用 Glass Button 提交过申请吗 获得批准了吗 我正在尝试使用彩色圆形按钮 但不想使用这些技巧 如何在 iPhone 上设置按钮背景颜色 https stackoverflow com questions 372731 ho
  • 如何同时关闭并弹出到视图控制器

    我的家庭视图控制器是Tabbarcontroller 从选项卡栏我导航到 A Viewcontroller TabarViewcontroller gt A 视图控制器 从A 视图控制器 我推 B 视图控制器 从B Viewcontroll
  • 核心蓝牙在后台进行广告和扫描

    我一直在尝试设置一个应用程序 使设备既扫描外围设备又作为外围设备进行广告 目标是当两个设备通过蓝牙发现彼此靠近时在后台被唤醒 从 Apple 文档来看 您似乎应该能够在后台运行 BLE 启用蓝牙中心和蓝牙外设后台模式 并且当一台设备位于前台
  • 如何改进 iOS 中的 TWTweetComposeViewController 代码?

    我已经实现了以下代码来进行 Twitter 共享 在我的代码中 我尝试测试 iOS 5 如果这不起作用 我会回到使用 ShareKit 的 Twitter 代码进行共享的旧方式 我向同事展示了代码 他建议我的代码可能有缺陷 我需要做两件事
  • 在 Objective C 中使用下划线作为属性名称前缀 [重复]

    这个问题在这里已经有答案了 我以前避免在变量名中使用下划线 这可能是我大学 Java 时代的遗留下来的 因此 当我在 Objective C 中定义属性时 我自然会这样做 In the header interface Whatever N
  • iOS 上每个选项的带有图像的操作表

    有没有办法在 iOS 上将图像添加到操作表中 与苹果在应用程序商店或苹果音乐应用程序上所做的一样 我对苹果文档的基本搜索表明我没有在操作表中子类化或添加子视图 UIActionSheet 并非设计为子类化 也不应向其层次结构添加视图 苹果文
  • Tween JS 基础知识之三个 JS 立方体

    我是 Tween JS 的新手 尝试使用 Tween 制作一个向右移动的简单动画 下面是我在 init 函数中的代码 我使用的是三个 JS var geometry new THREE CylinderGeometry 200 200 20
  • 为什么单个 Vec4 乘法会大大减慢我的 ogl es 2 片段着色器的速度?

    我正在为 iOS 设备编写 2D OpenGL 游戏 现在 我正在研究 iPad 第一代 上的性能 该游戏有 ogl 1 1 和 2 0 的代码路径 我可以通过 define 使用 ogl 2 0 时 分析器告诉我 我的渲染器利用率 相当稳
  • 自动布局和ios5

    我正在使用故事板 我已经使用了自动布局 但它不适用于 ios5 并且会崩溃 所以我想删除它 但是 如何取消选中自动布局 但如果我取消选中自动布局 我如何为 iPhone 4 和 5 设置屏幕 Regards 您可以在 IB 中禁用自动布局

随机推荐

  • 我可以使用 System.Linq.Expressions 动态生成异步方法吗?

    我知道编译器无法将异步 lambda 表达式转换为表达式树 但是是否可以手动生成表达式树 var expr Expression Lambda
  • 模拟实体框架模型?

    是否可以模拟 EF 模型 以便我可以测试使用模型类的代码 而无需删除散布在我的项目中的 LINQ to Entities 代码 或者是否需要建立一个测试数据库来让模型命中 您可以将 LINQ 代码包装在数据访问对象 http en wiki
  • 如何在批处理脚本中生成日期前四天的日期? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想在批处理脚本中生成日期前四天的日期 我检查了可用的解决方案 但它们看起来很复杂 任何帮助将不胜感激 我强烈同意 JosefZ 日期
  • 从函数返回 JSX

    我有一个组件需要检查多个选项并根据这些选项返回 因此 我创建了一个外部函数 在我的组件返回语句中调用该函数来确定将返回的格式 render const policy this props let deployment policy Depl
  • 如何更改 silverlight 5 中只读文本框的背景颜色?

    我想更改只读文本框的颜色 可以将默认颜色更改为白色 颜色 和文本框为
  • 如何正确通知 MediaScanner 有关文件夹的信息,即使在 Nexus/Kitkat 设备上也是如此?

    背景 我正在制作一个应用程序 将一些图像从互联网下载到定义为的特定文件夹中 final String pathToPutFiles Environment getExternalStoragePublicDirectory Environm
  • 字符串不匹配时的 Ansible 条件

    我正在尝试编写一个 Ansible 剧本 仅在 Nginx 尚未存在且当前版本不存在时才编译 Nginx 然而它每次都会编译 这是不可取的 这就是我所拥有的 shell usr local nginx sbin nginx v 2 gt 1
  • mediaelement.js - 如何隐藏音频控件?

    我正在尝试将 Mediaelement js 实现到视频和音频网站中 视频运行良好 但我需要做的是隐藏音频元素 这样它根本不会显示在页面上 并且 MEJS 音频控件酒吧不可见 音频的播放将通过根据需要播放 暂停音频的函数来处理 我尝试更改
  • Spring Batch:动态块大小

    我有步骤读取多个资源 我需要根据每个文件的行数更改块大小 Spring Batch是否可以具有动态块大小 或者有其他方法可以做到这一点 你可以做Spring Batch 步骤分区 对步骤进行分区 以便该步骤具有多个线程 每个线程并行处理一块
  • TextInputLayout:未聚焦时提示标签的颜色不同

    我想做的事 当使用嵌入 TextInputLayout 中的 EditText 时 我想 当标签失焦并漂浮在 EditText 上方时 将标签的颜色设置为绿色 因为用户已经输入了一些值 当标签失焦并位于 EditText 内时 将标签的颜色
  • 如何在Scala中使用优先级队列?

    我正在尝试在 Scala 版本 2 10 中实现 A 搜索 但我遇到了障碍 我不知道如何使用 Scala 的优先级队列 我有一组正方形 表示为 Int Int s 我需要插入它们的优先级由Ints 在 Python 中 您只有一个键 值对列
  • Ruby on Rails 绘制 gem 图形? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • svn 非 LF 行结束问题 svn:ignore on dump load

    我正在尝试使用转储文件将运行 svn 版本 1 2 3 的系统上的存储库 历史记录完整 迁移到运行 1 7 1 的系统 由于原始存储库是一个早期版本 因此使用svnrdump直接不是一个选择 我用了svnadmin dump然后将 8 GB
  • 在 Google appengine 中禁用版本特定的网址

    Google App Engine 支持版本特定的请求路由 如文档所示 here https cloud google com appengine docs standard python how requests are routed例如
  • 如何使用 Python、Pandas 创建 Decile 和 Quintile 列以根据大小对另一个变量进行排名?

    我有一个数据框 其中一列包含Investment代表交易者投资的金额 我想在数据框中创建 2 个新列 一个给出十分位数排名 另一个给出五分位数排名Investment尺寸 我希望 1 代表投资额最大的十分位数 10 代表投资额最小的十分位数
  • 用于光线/网格相交的 DirectX 11 计算着色器

    我最近将使用 D3DXIntersect 查找光线 网格交点的 DirectX 9 应用程序转换为 DirectX 11 由于 D3DXIntersect 在 DX11 中不可用 我编写了自己的代码来查找交点 该代码仅循环网格中的所有三角形
  • 使用 Pyinstaller 2.0 、PySide 1.1.2 Bindings 和 Qt 4.8 时如何在应用程序中包含图标

    what script looks like 工作应用程序应该是什么样子 在发布之前 我查看了以下问题并尝试将其用作使我的脚本正常工作的指南 但它的用处不大 PyInstaller 不会将 PyQt 的图像加载到 GUI https sta
  • 在 x 轴上绘制日期

    我正在尝试根据日期绘制信息 我有一个格式为 01 02 1991 的日期列表 我通过执行以下操作来转换它们 x parser parse date strftime Y m d 这使19910102 然后我尝试使用 num2date imp
  • 在 PowerShell 2.0 中加载 .NET 4.0 beta2 程序集

    我尝试从加载PresentationFramework dll NET http en wikipedia org wiki NET FrameworkPowerShell v2 0 中的 4 0 beta2 但它失败并出现以下错误 PS
  • 如何围绕对角线旋转 CALayer?

    我正在尝试实现一个翻转动画 用于像 iPhone 应用程序这样的棋盘游戏 动画应该看起来像一个旋转并改变其背面颜色的游戏片段 有点像黑白棋棋子 http en wikipedia org wiki Reversi 我已经成功创建了一个围绕其