125 lines
3.7 KiB
Swift
125 lines
3.7 KiB
Swift
import SwiftUI
|
||
import UIKit
|
||
|
||
struct GIFView: UIViewRepresentable {
|
||
let name: String
|
||
var onTap: (() -> Void)? = nil
|
||
|
||
func makeUIView(context: Context) -> UIImageView {
|
||
let imageView = UIImageView()
|
||
|
||
// 加载GIF
|
||
guard let url = Bundle.main.url(forResource: name, withExtension: "gif"),
|
||
let data = try? Data(contentsOf: url),
|
||
let image = UIImage.gif(data: data) else {
|
||
return imageView
|
||
}
|
||
|
||
imageView.image = image
|
||
imageView.contentMode = .scaleAspectFit
|
||
|
||
// 添加点击手势
|
||
if onTap != nil {
|
||
imageView.isUserInteractionEnabled = true
|
||
let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap))
|
||
imageView.addGestureRecognizer(tapGesture)
|
||
}
|
||
|
||
return imageView
|
||
}
|
||
|
||
func updateUIView(_ uiView: UIImageView, context: Context) {}
|
||
|
||
func makeCoordinator() -> Coordinator {
|
||
Coordinator(self)
|
||
}
|
||
|
||
class Coordinator: NSObject {
|
||
var parent: GIFView
|
||
|
||
init(_ parent: GIFView) {
|
||
self.parent = parent
|
||
}
|
||
|
||
@objc func handleTap() {
|
||
parent.onTap?()
|
||
}
|
||
}
|
||
}
|
||
|
||
// UIImage的扩展,用于处理GIF
|
||
extension UIImage {
|
||
static func gif(data: Data) -> UIImage? {
|
||
guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
|
||
print("无法创建CGImageSource")
|
||
return nil
|
||
}
|
||
|
||
let count = CGImageSourceGetCount(source)
|
||
var images = [UIImage]()
|
||
var duration: TimeInterval = 0
|
||
|
||
for i in 0..<count {
|
||
guard let cgImage = CGImageSourceCreateImageAtIndex(source, i, nil) else {
|
||
continue
|
||
}
|
||
|
||
duration += UIImage.gifDelayForImageAtIndex(source: source, index: i)
|
||
images.append(UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up))
|
||
}
|
||
|
||
if count == 1 {
|
||
return images.first
|
||
} else {
|
||
return UIImage.animatedImage(with: images, duration: duration)
|
||
}
|
||
}
|
||
|
||
static func gifDelayForImageAtIndex(source: CGImageSource, index: Int) -> TimeInterval {
|
||
var delay = 0.1
|
||
|
||
let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
|
||
let properties = cfProperties as? [String: Any] ?? [:]
|
||
let gifProperties = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any] ?? [:]
|
||
|
||
if let delayTime = gifProperties[kCGImagePropertyGIFUnclampedDelayTime as String] as? Double {
|
||
delay = delayTime
|
||
} else if let delayTime = gifProperties[kCGImagePropertyGIFDelayTime as String] as? Double {
|
||
delay = delayTime
|
||
}
|
||
|
||
if delay < 0.011 {
|
||
delay = 0.1
|
||
}
|
||
|
||
return delay
|
||
}
|
||
}
|
||
|
||
// 使用示例 - 带点击事件
|
||
struct GIFWithTapExample: View {
|
||
@State private var tapCount = 0
|
||
|
||
var body: some View {
|
||
VStack(spacing: 20) {
|
||
Text("点击GIF图片")
|
||
.font(.title)
|
||
|
||
GIFView(name: "Blind") {
|
||
// 点击事件处理
|
||
Router.shared.navigate(to: .blindBox(mediaType: .video))
|
||
}
|
||
.frame(width: 300, height: 300)
|
||
.border(Color.blue) // 可选:添加边框显示可点击区域
|
||
|
||
Text("点击次数: \(tapCount)")
|
||
.font(.subheadline)
|
||
}
|
||
}
|
||
}
|
||
|
||
struct GIFWithTapExample_Previews: PreviewProvider {
|
||
static var previews: some View {
|
||
GIFWithTapExample()
|
||
}
|
||
} |