簡體   English   中英

如何動畫SwiftUI中的圖片,播放一幀animation

[英]How to animate images in SwiftUI, to play a frame animation

我想在 SwiftUI 的圖像視圖中為圖像設置動畫

首先,我嘗試創建一些變量和一個 function 來切換 Image("imageVariable")。 它發生了變化,但沒有 animation 甚至嘗試了withAnimation { }方法

其次,我嘗試使用 UIKit 視圖。 在這里,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)
        }
    }
}

在方法 1 中我可以更改圖像但不能設置動畫,而在方法 2 中我可以設置動畫但不能控制它的大小

如果你想要一個健壯的跨平台 SwiftUI 實現動畫圖像,比如 GIF/APNG/WebP,我建議使用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
        })
    }
}

我使用UIViewRepresentable協議解決了這個問題。 在這里,我返回了一個帶有ImageViewUIView作為它的子視圖。 這讓我可以更好地控制孩子的大小等。

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

感謝 ImageAnimated 課程! 它派上用場了! 一件事,如果您打算傳入值,持續時間應該是一個變量而不是一個常量。否則您必須將持續時間排除在 ImageAnimated(imageSize:imageNames:) 調用之外。 :)

var duration: Double = 0.5

我創建了一個可以輕松重用的圖像動畫類

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)

在模型中:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM