SwiftUI:动画更改依赖于@ObjectBinding
Posted
技术标签:
【中文标题】SwiftUI:动画更改依赖于@ObjectBinding【英文标题】:SwiftUI: animate changes that depend on @ObjectBinding 【发布时间】:2019-06-15 19:37:26 【问题描述】:SwiftUI 具有使用 .animate()
的隐式动画和使用 .withAnimation()
的显式动画。但是,我不知道如何为图像更改设置动画:
struct ImageViewWidget : View
@ObjectBinding var imageLoader: ImageLoader
init(imageURL: URL)
imageLoader = ImageLoader(imageURL: imageURL)
var body: some View
Image(uiImage:
(imageLoader.data.count == 0) ? UIImage(named: "logo-old")! : UIImage(data: imageLoader.data)!)
.resizable()
.cornerRadius(5)
.frame(width: 120, height:120)
如果imageLoader
(BindableObject
)中没有数据,则此Image
的uiImage
参数将传递给old-logo
(占位符),并在异步加载后将其替换为正确的参数:
class ImageLoader : BindableObject
let didChange = PassthroughSubject<Data, Never>()
var data = Data()
didSet
didChange.send(data)
init(imageURL: URL)
print("Image loader being initted!")
let url = imageURL
URLSession.shared.dataTask(with: url) (data, _, _) in
guard let data = data else return
DispatchQueue.main.async
self.data = data
.resume()
我如何为这个变化设置动画,在data.count
不再是0
的那一刻,我们有了图像?说我想要一个淡出动画..
【问题讨论】:
在你的图片加载器中尝试设置withAnimation yourDataVariable = data
但是在哪里?那里没有 UI(我正在添加 ImageLoader
的代码)
你仍然可以这样做
你似乎很确定。你能发布一个答案,以便我测试、投票和接受吗?
【参考方案1】:
如果你想使用基于环境对象(或可观察对象)的显式动画,你需要在你的视图中创建一些状态。
您可以使用onReceive
对视图中的可观察对象的更改做出反应,然后使用显式动画修改您的状态。
struct ImageViewWidget: View
@ObservedObject var imageLoader: ImageLoader
@State var uiImage: UIImage = UIImage(named: "logo-old")!
init(imageURL: URL)
imageLoader = ImageLoader(imageURL: imageURL)
var body: some View
Image(uiImage: uiImage)
.resizable()
.cornerRadius(5)
.frame(width: 120, height: 120)
.onReceive(imageLoader.$data) data in
if data.count != 0
withAnimation
self.uiImage = UIImage(data: data)!
【讨论】:
【参考方案2】:您不必调用 .animate() 或 .withAnimation() 因为您只是在切换图像,您可以使用 .transition() 代替。 假设您已经使用@ObjectBinding(Beta5 中的@ObservedObject)成功更新了您的图像,您可以这样做:
var body: some View
if imageLoader.data.count == 0
Image(uiImage: UIImage(named: "logo-old")!)
.resizable()
.cornerRadius(5)
.frame(width: 120, height:120)
.transition(.opacity)
.animation(.easeInOut(duration:1))
else
Image(uiImage: UIImage(data: imageLoader.data)!)
.resizable()
.cornerRadius(5)
.frame(width: 120, height:120)
.transition(.opacity)
.animation(.easeInOut(duration:1))
如果你想让过渡更漂亮,你可以使用自定义视图修饰符:
struct ScaleAndFade: ViewModifier
/// True when the transition is active.
var isEnabled: Bool
// fade the content view while transitioning in and
// out of the container.
func body(content: Content) -> some View
return content
.scaleEffect(isEnabled ? 0.1 : 1)
.opacity(isEnabled ? 0 : 1)
//any other properties you want to transition
extension AnyTransition
static let scaleAndFade = AnyTransition.modifier(
active: ScaleAndFade(isEnabled: true),
identity: ScaleAndFade(isEnabled: false))
然后在您的 ImageViewWidget
中,将 .transition(.scaleAndFade)
添加到您的 Image 作为其视图修饰符
【讨论】:
这(你的第一个建议)不起作用。图像立即被替换,没有任何效果。我也认为它(不知何故)使图像同步加载。 抱歉,我忘了在 .transition 之后添加 `.animation(.easeInOut(duration:1))`,对我有用 还是不行。动画和过渡也不起作用以上是关于SwiftUI:动画更改依赖于@ObjectBinding的主要内容,如果未能解决你的问题,请参考以下文章
来自 @Published 属性的 SwiftUI 动画从视图外部更改