Merge pull request #13 from SDWebImage/feature_animatedimage_modifier
Feature animatedimage modifier
This commit is contained in:
commit
840b6725b5
28
README.md
28
README.md
|
@ -61,11 +61,10 @@ let package = Package(
|
|||
|
||||
## 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.
|
||||
|
||||
Supports the success/failure/progress changes event for custom handling.
|
||||
- [x] Supports the placeholder and detail options control for image loading as SDWebImage.
|
||||
- [x] 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.
|
||||
|
||||
|
@ -81,20 +80,25 @@ var body: some View {
|
|||
}
|
||||
```
|
||||
|
||||
+ Using `AnimatedImage` to play animation
|
||||
### Using `AnimatedImage` to play animation
|
||||
|
||||
```swift
|
||||
var body: some View {
|
||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
||||
.onFailure(perform: { (error) in
|
||||
// Error
|
||||
})
|
||||
.scaledToFit()
|
||||
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
||||
.scaledToFill()
|
||||
Group {
|
||||
AnimatedImage(url: URL(string: "https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"))
|
||||
.onFailure(perform: { (error) in
|
||||
// Error
|
||||
})
|
||||
.scaledToFit()
|
||||
AnimatedImage(data: try! Data(contentsOf: URL(fileURLWithPath: "/tmp/foo.webp")))
|
||||
.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.
|
||||
|
||||
## Demo
|
||||
|
|
|
@ -31,10 +31,18 @@ final class AnimatedImageLayout : ObservableObject {
|
|||
@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
|
||||
public struct AnimatedImage : ViewRepresentable {
|
||||
public struct AnimatedImage : PlatformViewRepresentable {
|
||||
@ObservedObject var imageModel = AnimatedImageModel()
|
||||
@ObservedObject var imageLayout = AnimatedImageLayout()
|
||||
@ObservedObject var imageConfiguration = AnimatedImageConfiguration()
|
||||
|
||||
var placeholder: PlatformImage?
|
||||
var webOptions: SDWebImageOptions = []
|
||||
|
@ -64,11 +72,11 @@ public struct AnimatedImage : ViewRepresentable {
|
|||
}
|
||||
#endif
|
||||
|
||||
func makeView(context: ViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
|
||||
func makeView(context: PlatformViewRepresentableContext<AnimatedImage>) -> AnimatedImageViewWrapper {
|
||||
AnimatedImageViewWrapper()
|
||||
}
|
||||
|
||||
func updateView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
|
||||
func updateView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
|
||||
view.wrapped.image = imageModel.image
|
||||
if let url = imageModel.url {
|
||||
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)
|
||||
}
|
||||
|
||||
func layoutView(_ view: AnimatedImageViewWrapper, context: ViewRepresentableContext<AnimatedImage>) {
|
||||
func layoutView(_ view: AnimatedImageViewWrapper, context: PlatformViewRepresentableContext<AnimatedImage>) {
|
||||
// AspectRatio
|
||||
if let _ = imageLayout.aspectRatio {
|
||||
// TODO: Needs layer transform and geometry calculation
|
||||
|
@ -190,6 +199,30 @@ public struct AnimatedImage : ViewRepresentable {
|
|||
view.setNeedsDisplay()
|
||||
#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
|
||||
|
@ -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
|
||||
extension AnimatedImage {
|
||||
public func onFailure(perform action: ((Error) -> Void)? = nil) -> AnimatedImage {
|
||||
|
|
|
@ -36,14 +36,14 @@ public typealias PlatformView = WKInterfaceObject
|
|||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
typealias ViewRepresentable = NSViewRepresentable
|
||||
typealias ViewRepresentableContext = NSViewRepresentableContext
|
||||
typealias PlatformViewRepresentable = NSViewRepresentable
|
||||
typealias PlatformViewRepresentableContext = NSViewRepresentableContext
|
||||
#endif
|
||||
#if os(iOS) || os(tvOS)
|
||||
typealias ViewRepresentable = UIViewRepresentable
|
||||
typealias ViewRepresentableContext = UIViewRepresentableContext
|
||||
typealias PlatformViewRepresentable = UIViewRepresentable
|
||||
typealias PlatformViewRepresentableContext = UIViewRepresentableContext
|
||||
#endif
|
||||
#if os(watchOS)
|
||||
typealias ViewRepresentable = WKInterfaceObjectRepresentable
|
||||
typealias ViewRepresentableContext = WKInterfaceObjectRepresentableContext
|
||||
typealias PlatformViewRepresentable = WKInterfaceObjectRepresentable
|
||||
typealias PlatformViewRepresentableContext = WKInterfaceObjectRepresentableContext
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue