【问题标题】:How to animate images in SwiftUI, to play a frame animation如何在 SwiftUI 中为图像设置动画,播放帧动画
【发布时间】:2019-07-22 17:52:34
【问题描述】:

我想在 SwiftUI 的图像视图中为图像设置动画

首先,我尝试创建一些变量和一个函数来切换 Image("imageVariable")。它改变了但没有动画甚至尝试了withAnimation { }方法

其次,我尝试使用 UIKit 视图。在这里,动画有效,但我无法应用 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)
        }
    }
}

在方法 1 中我可以更改图像但不能动画,而在方法 2 中我可以动画但不能控制它的大小

【问题讨论】:

  • 问候尝试#2...您不能简单地将both UI 动画 contentMode 移动到您的UIImageView ?此时UIViewRelatable 可以简单地将内容呈现为View 的完整大小。
  • @dfd 我会尝试在 UIView 中做大部分事情,然后简单地将其用于在 SwiftUI 中显示。
  • @kontiki 对图像进行动画处理是指在同一视图中播放 gif/帧动画,而不是视图转换。在这一点上,在 SwiftUI 中似乎是不可能的,因此放弃了。你认为没有 UIKit 也能做到吗?
  • 哦,如果是这样的话,那么使用 UIKit 可能会更好(至少目前是这样)。

标签: ios swift uiimageview swiftui


【解决方案1】:

如果您想要为动画图像(如 GIF/APNG/WebP)提供强大且跨平台的 SwiftUI 实现,我建议使用 SDWebImageSwiftUI。该框架基于现有的成功图片加载框架SDWebImage,并提供SwiftUI绑定。

要播放动画,请使用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
        })
    }
}

【讨论】:

    【解决方案2】:

    我使用UIViewRepresentable 协议解决了这个问题。在这里,我返回了 UIViewImageView 作为子视图。这让我可以更好地控制孩子的大小等。

    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")
            }
        }
    }
    

    【讨论】:

    • 经过长时间的寻找+研究后,这为我做到了。谢谢!我不得不将图像和动画图像移动到 makeUIView 函数中。不理想,但对我来说不是编译。
    【解决方案3】:

    在模型中:

    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
                }
            })
      }
    }
    

    在视图中:

    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)
             
    }
    }
    

    【讨论】:

      【解决方案4】:

      我创建了一个可以轻松重用的图像动画类

      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>) {
      
          }
      }
      

      使用方法:

      ImageAnimated(imageSize: CGSize(width: size, height: size), imageNames: ["loading1","loading2","loading3","loading4"], duration: 0.3)
                              .frame(width: size, height: size, alignment: .center)
      

      【讨论】:

      • 我已经尝试了图像动画类,它在单个视图上运行良好。如果我在 tabView 上实现它,动画就不会开始。如果我关闭 iPhone 并打开它,动画就会开始。也许我需要某种 .onAppear() 但我不知道我应该把它放在哪里......
      • 我不知道为什么 ImageAnimated() 在 Tabview() 中不起作用。我做错了什么?
      猜你喜欢
      • 1970-01-01
      • 2020-05-18
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 2019-11-05
      相关资源
      最近更新 更多