Add activity indicator implementation as well, using UIProgressView/NSProgressIndicator
This commit is contained in:
parent
6a2eb0264a
commit
40c5644569
|
@ -65,12 +65,8 @@ struct DetailView: View {
|
|||
.scaledToFit()
|
||||
} else {
|
||||
WebImage(url: URL(string:url), options: [.progressiveLoad])
|
||||
.onProgress { receivedSize, expectedSize in
|
||||
if (expectedSize > 0) {
|
||||
self.progress = CGFloat(receivedSize) / CGFloat(expectedSize)
|
||||
} else {
|
||||
self.progress = 1
|
||||
}
|
||||
.indicator { isAnimating, progress in
|
||||
ProgressIndicator(isAnimating, progress: progress)
|
||||
}
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
326B8488236335110011BDFB /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B8486236335110011BDFB /* ActivityIndicator.swift */; };
|
||||
326B8489236335110011BDFB /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B8486236335110011BDFB /* ActivityIndicator.swift */; };
|
||||
326B848A236335110011BDFB /* ActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B8486236335110011BDFB /* ActivityIndicator.swift */; };
|
||||
326B848C236335400011BDFB /* ProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B848B236335400011BDFB /* ProgressIndicator.swift */; };
|
||||
326B848D236335400011BDFB /* ProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B848B236335400011BDFB /* ProgressIndicator.swift */; };
|
||||
326B848E236335400011BDFB /* ProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B848B236335400011BDFB /* ProgressIndicator.swift */; };
|
||||
326B848F236335400011BDFB /* ProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B848B236335400011BDFB /* ProgressIndicator.swift */; };
|
||||
326E480A23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
|
@ -109,6 +113,7 @@
|
|||
324F61C6235E07EC003973B8 /* SDAnimatedImageInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageInterface.m; sourceTree = "<group>"; };
|
||||
326B84812363350C0011BDFB /* Indicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Indicator.swift; sourceTree = "<group>"; };
|
||||
326B8486236335110011BDFB /* ActivityIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicator.swift; sourceTree = "<group>"; };
|
||||
326B848B236335400011BDFB /* ProgressIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressIndicator.swift; sourceTree = "<group>"; };
|
||||
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewWrapper.swift; sourceTree = "<group>"; };
|
||||
32C43DCC22FD540D00BE87F5 /* SDWebImageSwiftUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageSwiftUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32C43DDC22FD54C600BE87F5 /* ImageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = "<group>"; };
|
||||
|
@ -176,6 +181,7 @@
|
|||
children = (
|
||||
326B84812363350C0011BDFB /* Indicator.swift */,
|
||||
326B8486236335110011BDFB /* ActivityIndicator.swift */,
|
||||
326B848B236335400011BDFB /* ProgressIndicator.swift */,
|
||||
);
|
||||
path = Indicator;
|
||||
sourceTree = "<group>";
|
||||
|
@ -438,6 +444,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32C43E1722FD583700BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848C236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84822363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3222FD5DE100BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480A23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
|
@ -453,6 +460,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32C43E1A22FD583700BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848D236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84832363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3322FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
|
@ -468,6 +476,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32C43E1D22FD583800BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848E236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84842363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3422FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
|
@ -483,6 +492,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
32C43E2022FD583800BE87F5 /* WebImage.swift in Sources */,
|
||||
326B848F236335400011BDFB /* ProgressIndicator.swift in Sources */,
|
||||
326B84852363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3522FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
|
|
|
@ -39,7 +39,6 @@ class ImageManager : ObservableObject {
|
|||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.progressBlock?(receivedSize, expectedSize)
|
||||
let progress: CGFloat
|
||||
if (expectedSize > 0) {
|
||||
progress = CGFloat(receivedSize) / CGFloat(expectedSize)
|
||||
|
@ -49,6 +48,7 @@ class ImageManager : ObservableObject {
|
|||
DispatchQueue.main.async {
|
||||
self.progress = progress
|
||||
}
|
||||
self.progressBlock?(receivedSize, expectedSize)
|
||||
}) { [weak self] (image, data, error, cacheType, finished, _) in
|
||||
guard let self = self else {
|
||||
return
|
||||
|
@ -58,6 +58,7 @@ class ImageManager : ObservableObject {
|
|||
}
|
||||
if finished {
|
||||
self.isLoading = false
|
||||
self.progress = 1
|
||||
if let image = image {
|
||||
self.successBlock?(image, cacheType)
|
||||
} else {
|
||||
|
|
|
@ -11,7 +11,7 @@ import SDWebImage
|
|||
|
||||
#if !os(watchOS)
|
||||
|
||||
// View Wrapper
|
||||
/// Use wrapper to solve tne `UIImageView`/`NSImageView` frame size become image size issue (SwiftUI's Bug)
|
||||
public class AnimatedImageViewWrapper : PlatformView {
|
||||
var wrapped = SDAnimatedImageView()
|
||||
var interpolationQuality = CGInterpolationQuality.default
|
||||
|
@ -54,4 +54,36 @@ public class AnimatedImageViewWrapper : PlatformView {
|
|||
}
|
||||
}
|
||||
|
||||
/// Use wrapper to solve the `UIProgressView`/`NSProgressIndicator` frame origin NaN crash (SwiftUI's bug)
|
||||
public class ProgressIndicatorWrapper : PlatformView {
|
||||
#if os(macOS)
|
||||
var wrapped = NSProgressIndicator()
|
||||
#else
|
||||
var wrapped = UIProgressView(progressViewStyle: .default)
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
public override func layout() {
|
||||
super.layout()
|
||||
wrapped.frame = self.bounds
|
||||
}
|
||||
#else
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
wrapped.frame = self.bounds
|
||||
wrapped.center = self.center
|
||||
}
|
||||
#endif
|
||||
|
||||
public override init(frame frameRect: CGRect) {
|
||||
super.init(frame: frameRect)
|
||||
addSubview(wrapped)
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
addSubview(wrapped)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import Swift
|
||||
import SwiftUI
|
||||
|
||||
/// An activity indicator (system style)
|
||||
public struct ActivityIndicator: PlatformViewRepresentable {
|
||||
@Binding var isAnimating: Bool
|
||||
|
||||
public init(_ isAnimating: Binding<Bool> = .constant(true)) {
|
||||
public init(_ isAnimating: Binding<Bool>) {
|
||||
self._isAnimating = isAnimating
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/// A container view to hold the indicator builder
|
||||
public struct Indicator : View {
|
||||
var builder: (Binding<Bool>, Binding<CGFloat>) -> AnyView
|
||||
public typealias Body = Never
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) DreamPiggy <lizhuoli1126@126.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A progress bar indicator (system style)
|
||||
public struct ProgressIndicator: PlatformViewRepresentable {
|
||||
@Binding var isAnimating: Bool
|
||||
@Binding var progress: CGFloat
|
||||
|
||||
public init(_ isAnimating: Binding<Bool>, progress: Binding<CGFloat>) {
|
||||
self._isAnimating = isAnimating
|
||||
self._progress = progress
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
public typealias NSViewType = ProgressIndicatorWrapper
|
||||
#elseif os(iOS) || os(tvOS)
|
||||
public typealias UIViewType = ProgressIndicatorWrapper
|
||||
#endif
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
public func makeUIView(context: UIViewRepresentableContext<ProgressIndicator>) -> ProgressIndicatorWrapper {
|
||||
let uiView = ProgressIndicatorWrapper()
|
||||
let view = uiView.wrapped
|
||||
view.progressViewStyle = .default
|
||||
return uiView
|
||||
}
|
||||
|
||||
public func updateUIView(_ uiView: ProgressIndicatorWrapper, context: UIViewRepresentableContext<ProgressIndicator>) {
|
||||
let view = uiView.wrapped
|
||||
if isAnimating {
|
||||
view.setProgress(Float(progress), animated: true)
|
||||
} else {
|
||||
if progress == 0 {
|
||||
view.isHidden = false
|
||||
view.progress = 0
|
||||
} else {
|
||||
view.isHidden = true
|
||||
view.progress = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
public func makeNSView(context: NSViewRepresentableContext<ProgressIndicator>) -> ProgressIndicatorWrapper {
|
||||
let nsView = ProgressIndicatorWrapper()
|
||||
let view = nsView.wrapped
|
||||
view.style = .bar
|
||||
view.isDisplayedWhenStopped = false
|
||||
view.controlSize = .small
|
||||
return nsView
|
||||
}
|
||||
|
||||
public func updateNSView(_ nsView: ProgressIndicatorWrapper, context: NSViewRepresentableContext<ProgressIndicator>) {
|
||||
let view = nsView.wrapped
|
||||
if isAnimating {
|
||||
view.isIndeterminate = false
|
||||
view.doubleValue = Double(progress) * 100
|
||||
view.startAnimation(nil)
|
||||
} else {
|
||||
if progress == 0 {
|
||||
view.isHidden = false
|
||||
view.isIndeterminate = true
|
||||
view.doubleValue = 0
|
||||
view.stopAnimation(nil)
|
||||
} else {
|
||||
view.isHidden = true
|
||||
view.isIndeterminate = false
|
||||
view.doubleValue = 100
|
||||
view.stopAnimation(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue