如何在 UIPageViewController 中为循环图像制作动画?
How do I animate looping images in a UIPageViewController?
我正在为我的应用构建演练,我 运行 遇到了一些奇怪的行为。
有关设置的一些上下文:在我的演练故事板中,我有一个名为 TutorialViewController
的视图控制器,它有一条欢迎消息、一个 'tutorial' 按钮和一个 'skip' 按钮。 'tutorial' 按钮触发了我的 WalkthroughViewController
的 segue,它有 next/back/close 个按钮和一个 UIPageIndicator
浮动在 UIContainerView
上。 UIContainerView
中嵌入了我的 WalkthroughPageViewController
。最后,我有一个 WalkthroughContentViewController
和两个 UIImageViews - contentImageView
和 contentImageViewMask
- 用作 WalkthroughPageViewController
的数据源。通过滑动或按下导航按钮,实例化下一个或上一个视图控制器(尽管它实际上只是重复使用我的 WalkthroughContentViewController
)。
目标:理想情况下,我希望通过演练的每一页的图像字符串数组不断循环动画。例如,如果第 1 页有一个包含 3 个图像字符串的数组,contentImageView
和 contentImageViewMask
将交替动画(通过 alpha 值)从 imageArray[0]
-> imageArray[1]
-> imageArray[2]
-> imageArray[0]
-> imageArray[1]
等
每个页面在 imageArray
中都有不同数量的图像字符串,我还没有想出如何顺利地遍历所有这些字符串。到目前为止,我的代码在数组中的前两个图像字符串之间进行动画处理,并且来自 this answer,它位于我的 WalkthroughContentViewController.swift
文件中:
override func viewDidLoad() {
super.viewDidLoad()
contentImageViewMask.alpha = 0
contentImageView.image = UIImage(named: imageArray[0])
UIView.animate(withDuration: 1.5, delay: 1.5, options: [UIViewAnimationOptions.autoreverse, UIViewAnimationOptions.repeat], animations: {
self.contentImageViewMask.image = UIImage(named: self.imageArray[1])
self.contentImageViewMask.alpha = 1
}, completion: nil)
}
上面的工作原理是,按下教程按钮后,第 1 页立即设置为 imageArray[1]
(不正确的行为),而第 2 页在 imageArray[0]
和 [=26] 之间平滑地动画=](正确的行为)。但是,在第 2 页上滑动超过一页会停用第 2 页上的动画。每隔一段时间,第 1 页会在此时开始正确设置动画,但我似乎无法找到一种可靠的方法来重现这一点。 Here's a video showing the behavior。我在连接 UIPageIndicator 和按钮操作之前拍摄了这个视频,所以请忽略它,但奇怪的是第 2 页动画仅通过滑动到页面发生。如果您通过下一步按钮转到第 2 页,则动画不起作用。
可能相关的两件事:1.) 在我的 WalkthroughPageViewController.swift
文件中,我已经为 UIPageViewControllerDataSource
、viewControllerBefore
和 viewControllerAfter
实现了两个必需的方法,和 2.) 在我的 WalkthroughPageViewController.swift
文件中,我有以下代码在滑动动画结束并且下一页完全显示时提醒委托人:
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
if let contentViewController = pageViewController.viewControllers?.first as? WalkthroughContentViewController {
currentIndex = contentViewController.index
walkthroughDelegate?.didUpdatePageIndex(currentIndex: contentViewController.index)
}
}
}
如有任何见解,我们将不胜感激。
在我看来,您是在与框架作斗争。如果你想要一个永久循环的自我替换图像,为什么不使用专门用于此目的的 UIImage 功能,即 animatedImage
?
对于任何想做类似但增加过渡灵活性的人(比如让图像淡出到下一个),this answer 帮助我实现了我的动画目标,即以一种不常见的方式在图像之间过渡不刺耳。
@IBOutlet weak var contentImageView: UIImageView!
var index = 0
let animationDuration: TimeInterval = 0.5
let switchingInterval: TimeInterval = 2.0
var imageStringArray: [String] = [""]
var images = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
for string in imageStringArray {
images.append(UIImage(named: string)!)
}
contentImageView.image = images[index]
animateImageView()
}
func animateImageView() {
CATransaction.begin()
CATransaction.setAnimationDuration(animationDuration)
CATransaction.setCompletionBlock {
DispatchQueue.main.asyncAfter(deadline: .now() + self.switchingInterval) {
self.animateImageView()
}
}
let transition = CATransition()
transition.type = kCATransitionFade
contentImageView.layer.add(transition, forKey: kCATransition)
contentImageView.image = images[index]
CATransaction.commit()
index = index < images.count - 1 ? index + 1 : 0
}
可能值得注意的是,该问题的原始答案是这样说的,"Implementing it as a custom image view would be better."
如果您只需要在图像之间设置动画并且转换无关紧要,那么 animatedImage
可能是一个更聪明的解决方案(如 matt 上面所说)。
contentImageView.image = UIImage.animatedImage(with: images, duration: 3)
我正在为我的应用构建演练,我 运行 遇到了一些奇怪的行为。
有关设置的一些上下文:在我的演练故事板中,我有一个名为 TutorialViewController
的视图控制器,它有一条欢迎消息、一个 'tutorial' 按钮和一个 'skip' 按钮。 'tutorial' 按钮触发了我的 WalkthroughViewController
的 segue,它有 next/back/close 个按钮和一个 UIPageIndicator
浮动在 UIContainerView
上。 UIContainerView
中嵌入了我的 WalkthroughPageViewController
。最后,我有一个 WalkthroughContentViewController
和两个 UIImageViews - contentImageView
和 contentImageViewMask
- 用作 WalkthroughPageViewController
的数据源。通过滑动或按下导航按钮,实例化下一个或上一个视图控制器(尽管它实际上只是重复使用我的 WalkthroughContentViewController
)。
目标:理想情况下,我希望通过演练的每一页的图像字符串数组不断循环动画。例如,如果第 1 页有一个包含 3 个图像字符串的数组,contentImageView
和 contentImageViewMask
将交替动画(通过 alpha 值)从 imageArray[0]
-> imageArray[1]
-> imageArray[2]
-> imageArray[0]
-> imageArray[1]
等
每个页面在 imageArray
中都有不同数量的图像字符串,我还没有想出如何顺利地遍历所有这些字符串。到目前为止,我的代码在数组中的前两个图像字符串之间进行动画处理,并且来自 this answer,它位于我的 WalkthroughContentViewController.swift
文件中:
override func viewDidLoad() {
super.viewDidLoad()
contentImageViewMask.alpha = 0
contentImageView.image = UIImage(named: imageArray[0])
UIView.animate(withDuration: 1.5, delay: 1.5, options: [UIViewAnimationOptions.autoreverse, UIViewAnimationOptions.repeat], animations: {
self.contentImageViewMask.image = UIImage(named: self.imageArray[1])
self.contentImageViewMask.alpha = 1
}, completion: nil)
}
上面的工作原理是,按下教程按钮后,第 1 页立即设置为 imageArray[1]
(不正确的行为),而第 2 页在 imageArray[0]
和 [=26] 之间平滑地动画=](正确的行为)。但是,在第 2 页上滑动超过一页会停用第 2 页上的动画。每隔一段时间,第 1 页会在此时开始正确设置动画,但我似乎无法找到一种可靠的方法来重现这一点。 Here's a video showing the behavior。我在连接 UIPageIndicator 和按钮操作之前拍摄了这个视频,所以请忽略它,但奇怪的是第 2 页动画仅通过滑动到页面发生。如果您通过下一步按钮转到第 2 页,则动画不起作用。
可能相关的两件事:1.) 在我的 WalkthroughPageViewController.swift
文件中,我已经为 UIPageViewControllerDataSource
、viewControllerBefore
和 viewControllerAfter
实现了两个必需的方法,和 2.) 在我的 WalkthroughPageViewController.swift
文件中,我有以下代码在滑动动画结束并且下一页完全显示时提醒委托人:
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
if let contentViewController = pageViewController.viewControllers?.first as? WalkthroughContentViewController {
currentIndex = contentViewController.index
walkthroughDelegate?.didUpdatePageIndex(currentIndex: contentViewController.index)
}
}
}
如有任何见解,我们将不胜感激。
在我看来,您是在与框架作斗争。如果你想要一个永久循环的自我替换图像,为什么不使用专门用于此目的的 UIImage 功能,即 animatedImage
?
对于任何想做类似但增加过渡灵活性的人(比如让图像淡出到下一个),this answer 帮助我实现了我的动画目标,即以一种不常见的方式在图像之间过渡不刺耳。
@IBOutlet weak var contentImageView: UIImageView!
var index = 0
let animationDuration: TimeInterval = 0.5
let switchingInterval: TimeInterval = 2.0
var imageStringArray: [String] = [""]
var images = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
for string in imageStringArray {
images.append(UIImage(named: string)!)
}
contentImageView.image = images[index]
animateImageView()
}
func animateImageView() {
CATransaction.begin()
CATransaction.setAnimationDuration(animationDuration)
CATransaction.setCompletionBlock {
DispatchQueue.main.asyncAfter(deadline: .now() + self.switchingInterval) {
self.animateImageView()
}
}
let transition = CATransition()
transition.type = kCATransitionFade
contentImageView.layer.add(transition, forKey: kCATransition)
contentImageView.image = images[index]
CATransaction.commit()
index = index < images.count - 1 ? index + 1 : 0
}
可能值得注意的是,该问题的原始答案是这样说的,"Implementing it as a custom image view would be better."
如果您只需要在图像之间设置动画并且转换无关紧要,那么 animatedImage
可能是一个更聪明的解决方案(如 matt 上面所说)。
contentImageView.image = UIImage.animatedImage(with: images, duration: 3)