[英]How to animate images in SwiftUI, to play a frame animation
I want to animate images in SwiftUI's Image view我想在 SwiftUI 的图像视图中为图像设置动画
First, I tried creating some variables and a function to toggle the Image("imageVariable").首先,我尝试创建一些变量和一个 function 来切换 Image("imageVariable")。 It changes but there is no animation even tried the
withAnimation { }
method它发生了变化,但没有 animation 甚至尝试了
withAnimation { }
方法
Secondly, I tried to use a UIKit view.其次,我尝试使用 UIKit 视图。 Here, the animation works but I can't apply the
resizable()
modifier or a set a fixed frame在这里,animation 有效,但我无法应用
resizable()
修饰符或设置固定框架
var images: [UIImage]! = [UIImage(named: "pushup001")!, UIImage(named: "pushup002")!]
let animatedImage = UIImage.animatedImage(with: images, duration: 0.5)
struct workoutAnimation: UIViewRepresentable {
func makeUIView(context: Self.Context) -> UIImageView {
return UIImageView(image: animatedImage)
}
func updateUIView(_ uiView: UIImageView, context: UIViewRepresentableContext<workoutAnimation>) {
}
}
struct WorkoutView: View {
var body: some View {
VStack {
workoutAnimation().aspectRatio(contentMode: .fit)
}
}
}
In method 1 I can change the image but not animate, while, in method 2 I can animate but not control it's size在方法 1 中我可以更改图像但不能设置动画,而在方法 2 中我可以设置动画但不能控制它的大小
If you want a robust and cross-platform SwiftUI implementation for animated images, like GIF/APNG/WebP, I recommend using SDWebImageSwiftUI .如果你想要一个健壮的跨平台 SwiftUI 实现动画图像,比如 GIF/APNG/WebP,我建议使用SDWebImageSwiftUI 。 This framework is based on exist success image loading framework SDWebImage and provides a SwiftUI binding.
该框架基于现有的成功图片加载框架SDWebImage并提供了 SwiftUI 绑定。
To play the animation, use AnimatedImage
view.要播放动画,请使用
AnimatedImage
视图。
var body: some View {
Group {
// Network
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
.onFailure(perform: { (error) in
// Error
})
}
}
I solved this using UIViewRepresentable
protocol.我使用
UIViewRepresentable
协议解决了这个问题。 Here I returned a UIView
with the ImageView
as it's subview.在这里,我返回了一个带有
ImageView
的UIView
作为它的子视图。 This gave me more control over the child's size, etc.这让我可以更好地控制孩子的大小等。
import SwiftUI
var images : [UIImage]! = [UIImage(named: "pushup001")!, UIImage(named: "pushup002")!]
let animatedImage = UIImage.animatedImage(with: images, duration: 0.5)
struct workoutAnimation: UIViewRepresentable {
func makeUIView(context: Self.Context) -> UIView {
let someView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
let someImage = UIImageView(frame: CGRect(x: 20, y: 100, width: 360, height: 180))
someImage.clipsToBounds = true
someImage.layer.cornerRadius = 20
someImage.autoresizesSubviews = true
someImage.contentMode = UIView.ContentMode.scaleAspectFill
someImage.image = animatedImage
someView.addSubview(someImage)
return someView
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<workoutAnimation>) {
}
}
struct WorkoutView: View {
var body: some View {
VStack (alignment: HorizontalAlignment.center, spacing: 10) {
workoutAnimation()
Text("zzzz")
}
}
}
thanks for the ImageAnimated class!感谢 ImageAnimated 课程! it comes in handy!
它派上用场了! one thing, the duration should be a var instead of a constant if you intend to pass the value in. otherwise you have to leave duration out of the ImageAnimated(imageSize:imageNames:) call.
一件事,如果您打算传入值,持续时间应该是一个变量而不是一个常量。否则您必须将持续时间排除在 ImageAnimated(imageSize:imageNames:) 调用之外。 :)
:)
var duration: Double = 0.5
I have created an image animation class that can be easily reused我创建了一个可以轻松重用的图像动画类
import SwiftUI
struct ImageAnimated: UIViewRepresentable {
let imageSize: CGSize
let imageNames: [String]
let duration: Double = 0.5
func makeUIView(context: Self.Context) -> UIView {
let containerView = UIView(frame: CGRect(x: 0, y: 0
, width: imageSize.width, height: imageSize.height))
let animationImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
animationImageView.clipsToBounds = true
animationImageView.layer.cornerRadius = 5
animationImageView.autoresizesSubviews = true
animationImageView.contentMode = UIView.ContentMode.scaleAspectFill
var images = [UIImage]()
imageNames.forEach { imageName in
if let img = UIImage(named: imageName) {
images.append(img)
}
}
animationImageView.image = UIImage.animatedImage(with: images, duration: duration)
containerView.addSubview(animationImageView)
return containerView
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<ImageAnimated>) {
}
}
The way to use it:使用方法:
ImageAnimated(imageSize: CGSize(width: size, height: size), imageNames: ["loading1","loading2","loading3","loading4"], duration: 0.3)
.frame(width: size, height: size, alignment: .center)
in model :在模型中:
var publisher : Timer?
@Published var index = 0
func startTimer() {
index = 0
publisher = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: {_ in
if self.index < count/*count of frames*/{
self.index += 1
}
else if let timer = self.publisher {
timer.invalidate()
self.publisher = nil
}
})
}
}
in view :鉴于:
struct MyAnimationView : View {
let width : CGFloat
let images = (0...60).map { UIImage(named: "tile\($0)")! }
@StateObject var viewmodel : MyViewModel
var body: some View {
Image(uiImage: images[viewmodel.index])
.resizable()
.frame(width: width, height: width, alignment: .center)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.