使用AsyncImage iOS 15匹配几何效果

beq87vna  于 11个月前  发布在  iOS
关注(0)|答案(2)|浏览(142)

请考虑以下示例:

struct ContentView: View {

    @State var showSplash: Bool = true
    @Namespace var animationNamespace

    var body: some View {
        ZStack {
            if showSplash {
                GeometryReader { geometry in
                    AsyncImage(url: URL(string: "https://picsum.photos/seed/864a5875-6d8b-43d6-8d65-04c5cfb13f3b/1920/1440")) { image in
                        image.resizable()
                        .scaledToFill()
                        .matchedGeometryEffect(id: "SplashImage", in: animationNamespace)
                        .transition(.move(edge: .bottom))
                        .frame(width: geometry.size.width)
                        .transition(.move(edge: .bottom))
                        .edgesIgnoringSafeArea(.all)
                        .clipped()
                    } placeholder: {
                        Color.gray
                    }
                }
                .onTapGesture {
                    toggleSplashScreen(false)
                }
            } else {
                ScrollView {
                    GeometryReader { geometry in
                        AsyncImage(url: URL(string: "https://picsum.photos/seed/864a5875-6d8b-43d6-8d65-04c5cfb13f3b/1920/1440")) { image in
                            image
                            image
                                .resizable()
                                .scaledToFill()
                                .matchedGeometryEffect(id: "SplashImage", in: animationNamespace)
                                .transition(.move(edge: .bottom))
                        } placeholder: {
                            Color.gray
                        }
                        .frame(width: geometry.size.width, height: 400)
                        .clipped()
                    }
                    .edgesIgnoringSafeArea(.all)
                    .onTapGesture {
                        toggleSplashScreen(true)
                    }
                }
            }
        }
    }
}

字符串
这里有一个helper方法:

private extension ContentView {
    func toggleSplashScreen(_ toggle: Bool) {
        withAnimation(.spring(response: 0.85, dampingFraction: 0.95)) {
            showSplash = toggle
        }
    }
}


这产生:
x1c 0d1x的数据
我注意到这里有两件事我想修正一下
1.在两种状态之间转换时 Flink 的白色效果。
1.我注意到,因为我们使用的是AsyncImage,当showSplash更改AsyncImage时,它只会偶尔命中placeholder块。因此,转换变得非常不稳定。我用assets文件中的静态图像测试了这个,然后转换变得平滑。我还尝试在AsyncImage上创建一个Caching机制,但它有时仍然会命中placeholder块。
我很乐意听到任何想法:)谢谢!

t9eec4r0

t9eec4r01#

我认为你可以做几件事来改善这一点。
首先,您可能会对SwiftUI维护视图身份的方式有一点抵触。SwiftUI确定何时可以重用现有结构而不是重新创建结构的方式之一是通过它在视图层次结构中的位置来确定。因此,当您切换结构时,您可以从:

GeometryReader 
  AsyncImage

字符串

ScrollView
  GeometryReader
    AsyncImage


因此,系统认为这是两个AsyncImage视图,因此正在重建视图(并重新加载图像)。我想这就是你的白色闪光的来源,因为你在动画的中间看到了灰色的占位符。如果你能让滚动视图保持在原来的位置,可能在不需要时禁用滚动(如果可能),则操作系统可以保持AsyncImage的身份。(请参见https://developer.apple.com/videos/play/wwdc2021/10022/
这就引出了你要研究的第二个领域。AsyncImage在从网络加载内容方面给你带来了极大的便利。不幸的是,它并不能加快通信速度。你的目标应该是让AsyncImage尽可能少地访问网络。
现在,调整大小的策略主要是调整图像的大小。这意味着,对于每次转换,你都在“击中网络”。(阅读将代码放在缓慢、尘土飞扬的土路上)。(较慢的部分)并调整显示它的视图的大小。一般的想法是让AsyncImage加载图像,然后通过设置视图帧的动画来控制如何设置图像的动画。
这就是我没什么帮助的地方。我对AsyncImage的了解还不够,不知道它是否能够实现这个策略。看起来它应该是......但我不知道它是不是。你可能不得不采取下载和存储图像的方式,将其作为与呈现它的视图分开的状态。
因此,我的建议是限制AsyncImage重新加载网络数据的次数。这涉及到帮助SwiftUI维护AsyncImage的身份,这样它就不必在每次创建视图时都重新加载。此外,尝试在视图上实现动画和缩放,而不是在图像上,因为重新缩放图像也需要重新加载网络数据。

lnvxswe2

lnvxswe22#

将matchedGeometryEffect与AsyncImage一起使用可能具有挑战性,特别是当图像纵横比在动画过程中发生变化时。我用来解决这个问题的可靠方法是将AsyncImage覆盖在Rectangle上,并将matchedGeometryEffect应用于Rectangle。
确保图像可以调整大小,并在.scaleToFit()或.scaleToFill()之间进行选择。然后通过修改矩形本身来控制图像的位置和大小。
如果您想要.scaleToFill(),则必须在应用matchedGeometryEffect修改器之前裁剪矩形。

ZStack {
    if showSplash {
        GeometryReader { geometry in
            Rectangle()
                .fill(.gray)
                .overlay {
                    AsyncImage(url: URL(string: "https://picsum.photos/seed/864a5875-6d8b-43d6-8d65-04c5cfb13f3b/1920/1440")) { image in
                        image
                            .resizable()
                            .scaledToFill()
                    } placeholder: {
                        Color.clear
                    }
                }
                .clipped()
                .matchedGeometryEffect(id: "SplashImage", in: animationNamespace)
                .frame(width: geometry.size.width)
        }
        .edgesIgnoringSafeArea(.all)
        .onTapGesture {
            toggleSplashScreen(false)
        }
    } else {
        ScrollView {
            GeometryReader { geometry in
                Rectangle()
                    .fill(.gray)
                    .edgesIgnoringSafeArea(.all)
                    .overlay {
                        AsyncImage(url: URL(string: "https://picsum.photos/seed/864a5875-6d8b-43d6-8d65-04c5cfb13f3b/1920/1440")) { image in
                            image
                                .resizable()
                                .scaledToFill()
                        } placeholder: {
                            Color.clear
                        }
                    }
                    .clipped()
                    .matchedGeometryEffect(id: "SplashImage", in: animationNamespace)
                    .frame(width: geometry.size.width, height: 400)
            }
            .onTapGesture {
                toggleSplashScreen(true)
            }
        }
    }
}

字符串

相关问题