Merge pull request #13 from SDWebImage/feature_animatedimage_modifier

Feature animatedimage modifier
This commit is contained in:
DreamPiggy 2019-10-05 15:06:28 +08:00 committed by GitHub
commit 840b6725b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 22 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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