Merge pull request #13 from SDWebImage/feature_animatedimage_modifier
Feature animatedimage modifier
This commit is contained in:
commit
840b6725b5
16
README.md
16
README.md
|
@ -61,11 +61,10 @@ let package = Package(
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
+ Using `WebImage` to load network image
|
### Using `WebImage` to load network image
|
||||||
|
|
||||||
Supports the placeholder and detail options control for image loading as SDWebImage.
|
- [x] Supports the placeholder and detail options control for image loading as SDWebImage.
|
||||||
|
- [x] Supports the success/failure/progress changes event for custom handling.
|
||||||
Supports the success/failure/progress changes event for custom handling.
|
|
||||||
|
|
||||||
Note: Unlike `UIImageView` in UIKit, SwiftUI's `Image` does not support animation. This `WebImage` using `Image` for internal implementation and supports static image format only.
|
Note: Unlike `UIImageView` in UIKit, SwiftUI's `Image` does not support animation. This `WebImage` using `Image` for internal implementation and supports static image format only.
|
||||||
|
|
||||||
|
@ -81,20 +80,25 @@ var body: some View {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
+ Using `AnimatedImage` to play animation
|
### Using `AnimatedImage` to play animation
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
Group {
|
||||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
||||||
.onFailure(perform: { (error) in
|
.onFailure(perform: { (error) in
|
||||||
// Error
|
// Error
|
||||||
})
|
})
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
||||||
.scaledToFill()
|
.customLoopCount(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- [x] Supports network image as well as local data and bundle image
|
||||||
|
- [x] Supports advanced control like loop count, incremental load, buffer size.
|
||||||
|
|
||||||
Note: `AnimatedImage` supports both image url or image data for animated image format. Which use the SDWebImage's [Animated ImageView](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#animated-image-50) for internal implementation.
|
Note: `AnimatedImage` supports both image url or image data for animated image format. Which use the SDWebImage's [Animated ImageView](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#animated-image-50) for internal implementation.
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
|
@ -31,10 +31,18 @@ final class AnimatedImageLayout : ObservableObject {
|
||||||
@Published var antialiased: Bool = false
|
@Published var antialiased: Bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration Binding Object
|
||||||
|
final class AnimatedImageConfiguration: ObservableObject {
|
||||||
|
@Published var incrementalLoad: Bool?
|
||||||
|
@Published var maxBufferSize: UInt?
|
||||||
|
@Published var customLoopCount: Int?
|
||||||
|
}
|
||||||
|
|
||||||
// View
|
// View
|
||||||
public struct AnimatedImage : ViewRepresentable {
|
public struct AnimatedImage : PlatformViewRepresentable {
|
||||||
@ObservedObject var imageModel = AnimatedImageModel()
|
@ObservedObject var imageModel = AnimatedImageModel()
|
||||||
@ObservedObject var imageLayout = AnimatedImageLayout()
|
@ObservedObject var imageLayout = AnimatedImageLayout()
|
||||||
|
@ObservedObject var imageConfiguration = AnimatedImageConfiguration()
|
||||||
|
|
||||||
var placeholder: PlatformImage?
|
var placeholder: PlatformImage?
|
||||||
var webOptions: SDWebImageOptions = []
|
var webOptions: SDWebImageOptions = []
|
||||||
|
@ -64,11 +72,11 @@ public struct AnimatedImage : ViewRepresentable {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
func makeView(context: ViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
|
func makeView(context: PlatformViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
|
||||||
AnimatedImageViewWrapper()
|
AnimatedImageViewWrapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
|
func updateView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
|
||||||
view.wrapped.image = imageModel.image
|
view.wrapped.image = imageModel.image
|
||||||
if let url = imageModel.url {
|
if let url = imageModel.url {
|
||||||
view.wrapped.sd_setImage(with: url, placeholderImage: placeholder, options: webOptions, context: webContext, progress: { (receivedSize, expectedSize, _) in
|
view.wrapped.sd_setImage(with: url, placeholderImage: placeholder, options: webOptions, context: webContext, progress: { (receivedSize, expectedSize, _) in
|
||||||
|
@ -82,10 +90,11 @@ public struct AnimatedImage : ViewRepresentable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureView(view, context: context)
|
||||||
layoutView(view, context: context)
|
layoutView(view, context: context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func layoutView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
|
func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
|
||||||
// AspectRatio
|
// AspectRatio
|
||||||
if let _ = imageLayout.aspectRatio {
|
if let _ = imageLayout.aspectRatio {
|
||||||
// TODO: Needs layer transform and geometry calculation
|
// TODO: Needs layer transform and geometry calculation
|
||||||
|
@ -190,6 +199,30 @@ public struct AnimatedImage : ViewRepresentable {
|
||||||
view.setNeedsDisplay()
|
view.setNeedsDisplay()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configureView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
|
||||||
|
// IncrementalLoad
|
||||||
|
if let incrementalLoad = imageConfiguration.incrementalLoad {
|
||||||
|
view.wrapped.shouldIncrementalLoad = incrementalLoad
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxBufferSize
|
||||||
|
if let maxBufferSize = imageConfiguration.maxBufferSize {
|
||||||
|
view.wrapped.maxBufferSize = maxBufferSize
|
||||||
|
} else {
|
||||||
|
// automatically
|
||||||
|
view.wrapped.maxBufferSize = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomLoopCount
|
||||||
|
if let customLoopCount = imageConfiguration.customLoopCount {
|
||||||
|
view.wrapped.shouldCustomLoopCount = true
|
||||||
|
view.wrapped.animationRepeatCount = customLoopCount
|
||||||
|
} else {
|
||||||
|
// disable custom loop count
|
||||||
|
view.wrapped.shouldCustomLoopCount = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
|
@ -241,6 +274,24 @@ extension AnimatedImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnimatedImage Modifier
|
||||||
|
extension AnimatedImage {
|
||||||
|
public func customLoopCount(_ loopCount: Int?) -> AnimatedImage {
|
||||||
|
imageConfiguration.customLoopCount = loopCount
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public func maxBufferSize(_ bufferSize: UInt?) -> AnimatedImage {
|
||||||
|
imageConfiguration.maxBufferSize = bufferSize
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public func incrementalLoad(_ incrementalLoad: Bool) -> AnimatedImage {
|
||||||
|
imageConfiguration.incrementalLoad = incrementalLoad
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Completion Handler
|
// Completion Handler
|
||||||
extension AnimatedImage {
|
extension AnimatedImage {
|
||||||
public func onFailure(perform action: ((Error) -> Void)? = nil) -> AnimatedImage {
|
public func onFailure(perform action: ((Error) -> Void)? = nil) -> AnimatedImage {
|
||||||
|
|
|
@ -36,14 +36,14 @@ public typealias PlatformView = WKInterfaceObject
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
typealias ViewRepresentable = NSViewRepresentable
|
typealias PlatformViewRepresentable = NSViewRepresentable
|
||||||
typealias ViewRepresentableContext = NSViewRepresentableContext
|
typealias PlatformViewRepresentableContext = NSViewRepresentableContext
|
||||||
#endif
|
#endif
|
||||||
#if os(iOS) || os(tvOS)
|
#if os(iOS) || os(tvOS)
|
||||||
typealias ViewRepresentable = UIViewRepresentable
|
typealias PlatformViewRepresentable = UIViewRepresentable
|
||||||
typealias ViewRepresentableContext = UIViewRepresentableContext
|
typealias PlatformViewRepresentableContext = UIViewRepresentableContext
|
||||||
#endif
|
#endif
|
||||||
#if os(watchOS)
|
#if os(watchOS)
|
||||||
typealias ViewRepresentable = WKInterfaceObjectRepresentable
|
typealias PlatformViewRepresentable = WKInterfaceObjectRepresentable
|
||||||
typealias ViewRepresentableContext = WKInterfaceObjectRepresentableContext
|
typealias PlatformViewRepresentableContext = WKInterfaceObjectRepresentableContext
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue