Skip to content

Supports AnimatedImage advanced control for custom loop count / max buffer size / incremental load #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand Down
59 changes: 55 additions & 4 deletions SDWebImageSwiftUI/Classes/AnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
12 changes: 6 additions & 6 deletions SDWebImageSwiftUI/Classes/SDWebImageSwiftUI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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