简体   繁体   English

SwiftUI 中的淡入淡出图像似乎不起作用

[英]Crossfading Images in SwiftUI doesn't seem to work

I'd like to achieve an an animated background that crossfades a bunch of images in SwiftUI.我想实现一个动画背景,在 SwiftUI 中对一堆图像进行淡入淡出。

I've managed to get an array of Colors to crossfade nicely between them using the following code snippets, but if I replace the array of Colors with an array of Images the same approach doesn't work.我已经使用以下代码片段设法使一组颜色在它们之间很好地交叉淡入淡出,但是如果我用一组图像替换颜色数组,则相同的方法不起作用。 The images are replaced, but not animated.图像被替换,但没有动画。 Yet both a Color and an Image are of type some View right?然而 Color 和 Image 都属于 some View 类型,对吗?

The following works:以下工作:

struct ImageBackgroundView: View {

  @State private var index = 0

  private let colors:[Color] = [.red, .blue, .green, .orange, .pink, .black]
  private let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()

  var body: some View {
    colors[self.index]
      .animation(.easeInOut(duration: 1))
      .onReceive(timer) { _ in
        print(self.index)
        self.index += 1
        if self.index > 5 { self.index = 0 }
      }
  }

but, if I replace the [Color] array with an array of type [Images], as follows, the images are transitioned, but the crossfade doesn't appear to work:但是,如果我用 [Images] 类型的数组替换 [Color] 数组,如下所示,图像会转换,但交叉淡入淡出似乎不起作用:

struct ImageBackgroundView: View {

  @State private var index = 0

  private let images = (1...8).map { Image("background\($0)") }
  private let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()

  var body: some View {
    images[self.index]
      .animation(.easeInOut(duration: 1))
      .onReceive(timer) { _ in
        print(self.index)
        self.index += 1
        if self.index > 5 { self.index = 0 }
      }
  }

Can anyone shed any light on why this might be the case?任何人都可以解释为什么会这样吗? Is it just a bug in SwiftUI at the present time?目前这只是 SwiftUI 中的一个错误吗?

I achieved a similar effect in a previous app using all sorts of addSubview calls animating the opacity of overlaying views - all sorts of stuff we shouldn't need to fiddle with in this brave new SwiftUI world right?我在以前的应用程序中使用各种 addSubview 调用实现了类似的效果,这些调用为覆盖视图的不透明度设置动画——在这个勇敢的新 SwiftUI 世界中,我们不需要摆弄各种东西,对吧?

This is interesting and it got me thinking.这很有趣,它让我思考。

You can use a flag, say show .您可以使用标志,例如show And a ZStack that holds your image object.还有一个ZStack保存你的image对象。 And then use transition combined with animation you want in that image .然后在该image使用transition与您想要的animation相结合。

But, only do that if show is true .但是,只有在showtrue时才这样做。

Attach the .onReceive event to the ZStack instead of your image ..onReceive事件附加到ZStack而不是您的image In that event, toggle the flag show .在这种情况下,切换标志show

@State private var index = 0
@State private var show = true

private let images = (1...8).map { Image("background\($0)") }
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

var body: some View {
    ZStack {
        if self.show {
            images[self.index]
                .transition(AnyTransition.opacity.animation(.easeInOut(duration: 1.0)))
        }
    }.onReceive(timer) { _ in
        print(self.index)
        self.index += 1
        self.show.toggle()
        if self.index > 4 { self.index = 0 }

    }
}

Voila!瞧!

在此处输入图片说明


Also, as far as I know, Color is not a View .另外,据我所知, Color不是View

A Color is a late-binding token: SwiftUI only resolves it to a concrete value just before using it in a given environment. Color 是后期绑定令牌:SwiftUI 仅在给定环境中使用它之前将其解析为具体值。

ref: https://developer.apple.com/documentation/swiftui/color参考: https : //developer.apple.com/documentation/swiftui/color

I changed your example a little and now background images changed with animation.我稍微改变了你的例子,现在背景图像随着动画而改变。 But I can't suggest, why the same things don't work either for Color or for Image .但我不能建议,为什么同样的事情对ColorImage不起作用。 So, here is my working example, maybe it will push you in right direction:所以,这是我的工作示例,也许它会将您推向正确的方向:

struct AnimatedBackground: View {

    @State private var index = 0

    private let images: [Image] = ["trash", "star", "circle", "circle.fill", "square", "cloud"].map{ Image(systemName: $0) }
    private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()

    var body: some View {
        ZStack {

            ForEach(images.indices, id: \.self) { imageIndex in
                self.images[imageIndex]
                    .resizable()
                    .transition(.opacity)
                    .opacity(imageIndex == self.index ? 1 : 0)
            }

        }
        .onReceive(timer) { _ in
            withAnimation {
                self.index = self.index < self.images.count - 1 ? self.index + 1 : 0
            }
        }
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM