【问题标题】:UIImage animations don't work in a view pushed without animationUIImage 动画在没有动画推送的视图中不起作用
【发布时间】:2013-02-15 13:49:29
【问题描述】:

我有一个视图控制器,它的视图包含一个执行动画的UIImageView

//AnimationViewController::ViewDidLoad event:
var ctlAnimations = new UIImageView();

ctlAnimations.AnimationImages = list.ToArray();  //<--list contains the UIImages
ctlAnimations.AnimationDuration = 1.0 * list.Count;
ctlAnimations.StartAnimating();

this.Add(ctlAnimations);

这非常有效:当我将 AnimationViewController 推送到导航堆栈时,它会显示 UIImage 并为其设置动画。

但现在我需要用自定义动画过渡显示AnimationViewController

var transition = CATransition.CreateAnimation ();
transition.Duration = 0.3f;
transition.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);
transition.Type = CATransition.TransitionFade;
this.View.Layer.AddAnimation (transition, "fade");
//viewController is being pushed with animated=false, because we have a custom animation
base.PushViewController (viewController, false);  
this.View.Layer.RemoveAnimation("fade");

完美运行,因为新视图使用指定的自定义动画过渡到位。

但是当我使用动画过渡AnimationViewController 推入堆栈时,它会显示,但动画不会运行。相反,它显示动画的第一帧(列表中的第一张图像),并且不运行它。

因此,关于过渡的某些事情破坏了在新视图控制器中为 UIImage 设置动画的能力,但我根本不知道该怎么做。

更新:我注意到如果我点击 NavigationController 的后退按钮,然后离开后退按钮并松开(所以我实际上并没有返回),动画就会开始玩!

【问题讨论】:

  • - 当您点击AnimationViewController 中的任何按钮时,UIImageView 动画也会开始;
  • 赏金怎么了?没有获奖吗?
  • 还没有,因为没有一个答案让我更接近解决方案。在这种情况下我该怎么办?
  • 不确定它是否相关,但我注意到的一件事是您正在立即调用 RemoveAnimation,而不是将其设置为在完成时将其删除。

标签: iphone ios xamarin.ios


【解决方案1】:

PushViewController 的工作方式如下:在当前视图控制器之上放置下一个视图控制器,您可以说是推入堆栈。从 Apple 文档中可以清楚地看出,您需要使用或不使用动画来推送视图控制器。

解决方法:

  1. 设置下一个视图控制器的视图 x 位置的框架超出 屏幕右侧
  2. 假设屏幕宽度为320,则设置next的x位置 查看为 320。
  3. 将下一个视图作为子视图添加到现有视图中。
  4. 现在制作您的自定义动画。

另一种解决方法:(虽然开销更大)

  • 以编程方式拍摄当前视图的快照。
  • 添加快照图像作为下一个视图控制器的初始视图。
  • 现在推送没有动画的视图控制器。 (用户仍会看到旧视图)
  • 在新视图控制器的 viewDidAppear 中启动您的自定义动画。

[我必须警告您,这种拍摄快照的方法可能会给您在旧设备上带来一点延迟。较新的设备速度足够快,您不会看到任何延迟]

如果您在实施这些解决方案时遇到任何问题,请告诉我。

【讨论】:

  • 第二个解决方法肯定有效,因为正如您在更新动画中所说,当您点击返回按钮时开始播放。试试看吧
  • 我今天会试试这些,但我真的不明白为什么这些是必要的。为什么我的动画视图一开始没有播放?
  • 如果我弄错了,请原谅我,但是您的第二次解决听起来很糟糕,他在某个地方有一个实际的错误,解决伪造的屏幕截图听起来像是营销人员会告诉开发人员这样做,以便他们可以销售蒸汽软件
【解决方案2】:

尝试将动画位放入 ViewDidAppear 而不是 ViewDidLoad。此外,尝试使用断点和 NSLogs 来跟踪动画之后发生的情况,从 ViewDidLoad 和 ViewDidAppear 开始。尝试让动画永远重复,这样您就可以查看它是否一直在制作动画。

【讨论】:

  • 我尝试将其移动到 viewDidAppear 并得到相同的结果。动画已经永远重复了,所以我认为很明显它永远不会开始动画。
【解决方案3】:

我也很好奇罪魁祸首在这里。为什么某些情况下动画无法正确显示?

我的理论是您将动画代码放在 viewWillAppear 而不是 viewDidAppear 中。动画代码在 WILL 或 SHOULD 方法中无法正常运行。

能否请您回复导致问题的原因?

【讨论】:

    【解决方案4】:

    怀疑 #1

    我打赌你的代码没有被调用,因为它在 ViewDidLoad 中。我相信您正在创建自定义视图堆栈,这意味着您需要使用 Cocoa 中的 ChildViewController 方法。

    我不熟悉 MonoTouch(我只写纯 CocoaTouch),所以这可能不是 100% 正确

    我会安慰你的 viewDidLoad 和 viewDidAppear 方法,并绝对确保它们被调用。我怀疑 viewDidLoad 不是。这导致无法在 UIImageView 上调用 viewDidLoad。

    在您的代码中,您可能需要(来自objective-c):

    [self addChildViewController:viewController];
    // OR?
    [base addChildViewController:viewController];
    

    这会告诉“父”视图控制器 Child 已经可见,因此在适当的时候调用 viewDidLoad/Appear 和 Unload/Disappear 方法。这在 MonoTouch 中可能不存在,或者 Push 方法可能没有完全实现,因此您可能需要做一些 hacky(bad)的事情,例如手动调用 viewDidLoad 方法。

    怀疑#2

    也可能是您的“列表”变量(保存图像的变量)为零。如果发生这种情况,动画将不会运行。或者它可能与动画的持续时间有关,尝试将其设置为使其永远重复的任何内容。确保它没有以某种方式运行REAL FAST,而你只是错过了它。

    开始哲学思考
    要么,要么开始学习实际的 Cocoa 开发 :) 不意味着火焰,但绝对意味着认真,您将遇到尝试通过翻译层开发应用程序的问题(自定义语言桥旨在绕过编写基础语言框架/应用程序/平台)。

    Titanium/MonoTouch/PhoneGap 永远不会产生像真正的 Objective-C 那样健壮或高质量的应用程序。除此之外,一旦你学习了 Cocoa,它会改变你写其他东西的方式,我怀疑你会想回去。正如同名精彩网站所说,“可可是我的女朋友”

    【讨论】:

    • 怀疑#3:动画代码应该在主线程上调用来执行
    • 这是一个很好的怀疑。但是,如果他在搞乱线程,那么视图就不太可能显示出来。 UI 代码应该只在主线程上工作
    • 我没有对线程做任何事情。在 viewDidLoad 中,我创建了一个 UIImageView,向其中添加一些图像,并将 UIImageView 添加到当前视图。列表变量不为空也不为空。动画会永远重复。
    • 关于使用 Cocoa,一个答案是通过使用 MonoTouch,我可以将大部分代码移植到 Android,而不是从头开始使用 Java。另一个答案是 MonoTouch 是一个非常薄的抽象层,非常紧密地反映了 iOS 中的类层次结构,而且我还没有遇到过我无法访问 iOS 暴露的东西的情况。我精通 C#,我根本无法想象 ObjectiveC 对我来说可以如此健壮,无论如何,考虑到语法和内存管理需要如此小心的需要。
    • 请注意,使用 ARC 进行内存管理简单,只有少数情况需要了解它。了解 MonoTouch 背后的原因,请小心:)。 Android 是一个大章鱼,支持数百种不同的设备。一刀切的解决方案甚至在 Java 世界中都不起作用,更不用说用于生成 Java 和 Objective-C 的东西了。
    【解决方案5】:

    让我来谈谈IOS中的UI。在 IOS 中,对 UI 元素的访问仅限于单个线程。

    除非您正在运行动画,否则单线程将始终是 mainThread。

    因此,当您在同一实例中执行多个动画时,您必须使用

    1. 开始动画。

    2. setFrame(或)一些改变 UI 元素状态的方法。

    3. 对您计划进行动画处理的所有对象重复第 2 步。

    4. comitAnimations 一次执行所有动画。 (使用提交动画确保所有动画都在同一个线程上执行)

    所以,我想这就是你的情况。

    1. Viewcontroller 启动动画以将视图控制器推入堆栈。

    2. 图像视图在完成第一个动画之前开始另一个动画。

    查看链接以获得清晰的想法link1link2

    让我们进入解决方案

    将名为 ctlAnimations 的 ivar 和保留属性添加到您的类中

    在 ViewDidLoad(或)ViewDidAppear 中

    self.ctlAnimations = new UIImageView();
    ctlAnimations.image=(UIImage*)[list.toArray() objectAtIndex:0];
    this.Add(ctlAnimations);
    [self performSelector:@selector(startAnimatingImage) afterDelay:0.1];
    

    使用以下代码创建一个名为 startAnimatingImage 的私有方法

    self.ctlAnimations.AnimationImages = list.ToArray();
    ctlAnimations.AnimationDuration = 1.0 * list.Count;
    ctlAnimations.StartAnimating();
    

    简而言之,我们只是在第一个动画发生时显示了第一张图像,然后我们将动画开始延迟 1 秒,以便它在第一个动画之后执行,然后开始为图像制作动画。

    去试试吧

    【讨论】:

      【解决方案6】:

      有主线程的概念。所以 UIAnimation 实际上是在主线程上工作的,同时可能会发生另一个任务在同一个主线程上执行的情况。所以这种情况就像 IOS 会根据每个进程的进程 ID 一次给予优先权,对于您需要为相同操作创建后台线程的解决方案。

      【讨论】:

        【解决方案7】:

        好吧,我从来不知道问题出在哪里,但事实证明UIImage 中存在某种内存泄漏,以至于在某些手机上我的代码崩溃了。

        所以我重写了它来手动制作动画。现在我设置了一个计时器并保留了一个帧索引变量,每次计时器响起时我都会自己更改图像。这相当于同一件事,事实证明它解决了这个问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-18
          • 1970-01-01
          • 2015-10-15
          • 2012-11-03
          • 2015-09-09
          • 2017-12-13
          • 1970-01-01
          相关资源
          最近更新 更多