Closed ClaudiuStefaniga closed 1 year ago
Is there any update on this issue? I've been facing something similar.
@ClaudiuStefaniga @guseulalio
i had success setting imageview.frame = .zero
in the UIViewRepresentable, and then setting the frame in the SwiftUI viewbuilder GIFView().frame(width: 50, height: 50)
Same issue here, the gif took the whole screen
Any update on this issue? I tried what @yyl0 suggested but it doesn't work...
Similarly. I tried what @yyl0 suggested and it didn't work for me.
Instead of using directly ImageView, we can use it as below:
let view = UIView()
let gif = try! UIImage(gifName: named)
let imageView = UIImageView(gifImage: gif, loopCount: loopCount)
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
NSLayoutConstraint.activate([
imageView.heightAnchor.constraint(equalTo: view.heightAnchor),
imageView.widthAnchor.constraint(equalTo: view.widthAnchor)
])
return view
}```
Following solution is working for me, Xcode 13.3, SwiftUI 5.6
import SwiftUI
import SwiftyGif
struct A9_SwiftyGif2: View {
@State var playGif = false
@State var gifName = "alternating_pogo"
var body: some View {
VStack {
HStack {
SwiftyGif(name: gifName, loopCount: 100, playGif: $playGif)
.frame(width: 100, height: 100)
Spacer()
SwiftyGif(name: "pokeball")
.frame(width: 100, height: 100)
}
.padding()
Spacer()
Button(action: {
self.playGif.toggle()
}) {
Text("toggle")
}
Spacer()
}
}
}
struct A9_SwiftyGif2_Previews: PreviewProvider {
static var previews: some View {
A9_SwiftyGif2()
}
}
class UIGIFImageView: UIView {
private var image = UIImage()
var imageView = UIImageView()
private var data: Data?
private var name: String?
private var loopCount: Int?
open var playGif: Bool?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(name: String, loopCount: Int, playGif: Bool) {
self.init()
self.name = name
self.loopCount = loopCount
self.playGif = playGif
createGIF()
}
convenience init(data: Data, loopCount: Int, playGif: Bool) {
self.init()
self.data = data
self.loopCount = loopCount
self.playGif = playGif
createGIF()
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = bounds
self.addSubview(imageView)
}
func createGIF() {
do {
if let data = data {
image = try UIImage(gifData: data)
} else {
image = try UIImage(gifName: self.name!)
}
} catch {
print(error)
}
imageView = UIImageView(gifImage: image, loopCount: loopCount!)
// .scaleAspectFit keeps the aspect ratio of the gif
imageView.contentMode = .scaleAspectFit
}
}
struct SwiftyGif: UIViewRepresentable {
private let data: Data?
private let name: String?
private let loopCount: Int?
@Binding var playGif: Bool
init(data: Data, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = data
self.name = nil
self.loopCount = loopCount
self._playGif = playGif
}
init(name: String, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = nil
self.name = name
self.loopCount = loopCount
self._playGif = playGif
}
func makeUIView(context: Context) -> UIGIFImageView {
var gifImageView: UIGIFImageView
if let data = data {
gifImageView = UIGIFImageView(data: data, loopCount: loopCount!, playGif: playGif)
} else {
gifImageView = UIGIFImageView(name: name!, loopCount: loopCount!, playGif: playGif)
}
return gifImageView
}
func updateUIView(_ gifImageView: UIGIFImageView, context: Context) {
if playGif {
gifImageView.imageView.startAnimatingGif()
} else {
gifImageView.imageView.stopAnimatingGif()
}
}
}
I have come up with another modified version that allow user to switch the gif image
import SwiftUI
import SwiftyGif
struct A9_SwiftyGif_final: View {
@State private var playGif = false
@State private var gifName = "alternating_pogo"
var body: some View {
VStack {
SwiftyGif(name: gifName, playGif: $playGif)
// TODO: why cannot use width: .infinity
.frame(width: 300)
Spacer()
Button {
gifName = (gifName == "alternating_pogo") ? "lunge_jump":"alternating_pogo"
} label: {
Text("Change Gif")
.frame(maxWidth: .infinity)
}
.buttonStyle(BorderedButtonStyle())
Spacer()
Button {
playGif.toggle()
} label: {
Text("Stop/Start Play")
.frame(maxWidth: .infinity)
}
.buttonStyle(BorderedButtonStyle())
Spacer()
}
}
}
import Foundation
import UIKit
import SwiftUI
// Rendering GIFs in UIKIt
class UIGIFImageView: UIView {
private var image = UIImage()
var imageView = UIImageView()
private var data: Data?
private var name: String?
private var loopCount: Int?
private var playGif: Bool?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(name: String, loopCount: Int, playGif: Bool) {
self.init()
self.name = name
self.loopCount = loopCount
self.playGif = playGif
self.layoutSubviews()
}
convenience init(data: Data, loopCount: Int, playGif: Bool) {
self.init()
self.data = data
self.loopCount = loopCount
self.playGif = playGif
self.layoutSubviews()
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = bounds
self.addSubview(imageView)
}
func updateGIF(name: String, data: Data?, loopCount: Int) {
do {
if let data = data {
image = try UIImage(gifData: data)
} else {
print(name)
image = try UIImage(gifName: name)
}
} catch {
print(error)
}
if let subview = self.subviews.first as? UIImageView {
// if new gif, remove old to show new
if image.imageData != subview.gifImage?.imageData {
imageView = UIImageView(gifImage: image, loopCount: loopCount)
imageView.contentMode = .scaleAspectFit
subview.removeFromSuperview()
}
} else {
print("error: no existing subview")
}
}
}
struct SwiftyGif: UIViewRepresentable {
private let data: Data?
private let name: String?
private let loopCount: Int?
@Binding var playGif: Bool
init(data: Data, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = data
self.name = nil
self.loopCount = loopCount
self._playGif = playGif
}
init(name: String, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = nil
self.name = name
self.loopCount = loopCount
self._playGif = playGif
}
func makeUIView(context: Context) -> UIGIFImageView {
var gifImageView: UIGIFImageView
if let data = data {
gifImageView = UIGIFImageView(data: data, loopCount: loopCount!, playGif: playGif)
} else {
gifImageView = UIGIFImageView(name: name!, loopCount: loopCount!, playGif: playGif)
}
return gifImageView
}
func updateUIView(_ gifImageView: UIGIFImageView, context: Context) {
gifImageView.updateGIF(name: name ?? "", data: data, loopCount: loopCount!)
if playGif {
gifImageView.imageView.startAnimatingGif()
} else {
gifImageView.imageView.stopAnimatingGif()
}
}
}
Thank your for the solution !
macOS version based on @louislung's code:
class NSGIFImageView: NSView {
private var image = NSImage()
var imageView = NSImageView()
private var data: Data?
private var name: String?
private var loopCount: Int?
private var playGif: Bool?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(name: String, loopCount: Int, playGif: Bool) {
self.init()
self.name = name
self.loopCount = loopCount
self.playGif = playGif
self.layout()
}
convenience init(data: Data, loopCount: Int, playGif: Bool) {
self.init()
self.data = data
self.loopCount = loopCount
self.playGif = playGif
self.layout()
}
override func layout() {
super.layout()
imageView.frame = bounds
self.addSubview(imageView)
}
func updateGIF(name: String, data: Data?, loopCount: Int) {
do {
if let data = data {
image = try NSImage(gifData: data)
} else {
print(name)
image = try NSImage(gifName: name)
}
} catch {
print(error)
}
if let subview = self.subviews.first as? NSImageView {
// if new gif, remove old to show new
if image.imageData != subview.gifImage?.imageData {
imageView = NSImageView(gifImage: image, loopCount: loopCount)
imageView.imageScaling = .scaleProportionallyDown
subview.removeFromSuperview()
}
} else {
print("error: no existing subview")
}
}
}
struct SwiftyGif: NSViewRepresentable {
typealias NSViewType = NSGIFImageView
private let data: Data?
private let name: String?
private let loopCount: Int?
@Binding var playGif: Bool
init(url: URL) {
self.data = try? Data(contentsOf: url)
self.name = nil
self.loopCount = -1
self._playGif = .constant(true)
}
init(data: Data, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = data
self.name = nil
self.loopCount = loopCount
self._playGif = playGif
}
init(name: String, loopCount: Int = -1, playGif: Binding<Bool> = .constant(true)) {
self.data = nil
self.name = name
self.loopCount = loopCount
self._playGif = playGif
}
func makeNSView(context: Context) -> NSGIFImageView {
var gifImageView: NSGIFImageView
if let data = data {
gifImageView = NSGIFImageView(data: data, loopCount: loopCount!, playGif: playGif)
} else {
gifImageView = NSGIFImageView(name: name!, loopCount: loopCount!, playGif: playGif)
}
return gifImageView
}
func updateNSView(_ gifImageView: NSGIFImageView, context: Context) {
gifImageView.updateGIF(name: name ?? "", data: data, loopCount: loopCount!)
if playGif {
gifImageView.imageView.startAnimatingGif()
} else {
gifImageView.imageView.stopAnimatingGif()
}
}
}
in case this helps another seeking SwiftUI usage.
i have a gif coming from a remote URL. the parent view has an ObservableObject
that publishes that URL. here's my gif view:
struct AnimatedGifView: UIViewRepresentable {
@Binding var url: URL
func makeUIView(context: Context) -> UIImageView {
let imageView = UIImageView(gifURL: self.url)
imageView.contentMode = .scaleAspectFit
return imageView
}
func updateUIView(_ uiView: UIImageView, context: Context) {
uiView.setGifFromURL(self.url)
}
}
and here's the call-site in the parent where viewModel
is the ObservableObject
:
AnimatedGifView(url: Binding(get: { self.viewModel.gif.url }, set: { _ in }))
Hello, I am trying to use SwiftyGif with SwiftUI but for some reasons the gif is resizing after I started even though I set a fixed frame. Here is my code:
` struct ContentView: View { @State var playGif = false
}
struct SwiftyGif: UIViewRepresentable { @Binding var playGif: Bool
} `