scroll与scrollTargetBehavior冲突?

问题描述 投票:0回答:1

我尝试在 SwiftUI 中复制 Snapchat 相机滤镜滚动。

当我手动滚动时,由于新的 iOS 17 滚动 API,它运行良好,它以每个圆圈为中心。但点击时它不起作用,scrollTo方法不保留圆的中心,我尝试了很多锚点但无法使其适用于所有圆。有时它适用于最后一个圆圈,但不适用于第一个圆圈。

就像你在下面看到的那样,在 gif 的开头,我正在滚动手势(工作),然后我点击(不再工作)。

如果我删除scrollTargetBehavior(.viewAligned)和scrollTargetLayout,则scrollTo正在工作。

这是重现该问题的简化代码:


import SwiftUI

@main
struct scrollApp: App {
    var body: some Scene {
        WindowGroup {
            GeometryReader(content: { outerProxy in
                ScrollViewReader(content: { proxy in
                    ScrollView(.horizontal, showsIndicators: false) {
                        LazyHStack(spacing: 0) {
                            ForEach(0...10, id: \.self) { index in
                                Circle()
                                    .frame(width: 100, height: 100)
                                    .foregroundStyle(.primary)
                                    .id(index)
                                    .onTapGesture {
                                        print("tap \(index)")
                                        withAnimation {
                                            proxy.scrollTo(index, anchor: .center)
                                        }
                                    }
                            }
                        }
                        .padding(.horizontal, outerProxy.size.width * 0.5 - 100/2)
                        .scrollTargetLayout()
                    }
                    .scrollTargetBehavior(.viewAligned)
                    .overlay {
                        Circle()
                            .stroke(.red, lineWidth: 10)
                            .frame(width: 100, height: 100)
                    }
                })
            })
            
        }
    }
}

swiftui scroll ios17
1个回答
0
投票

我已经尝试过你的代码,但有两个问题:

1. 您正在使用填充来

offset
修改内容以使其居中 2. 设置为
anchor
功能的
proxy.scrollTo
.center
,而根据我的测试,它必须是
.leading
。这可能就是它无法与
.scrollPosition
一起使用的原因。

所以,这就是解决方案:

@State private var activeIndex: Int?

var body: some View {
    GeometryReader { outerProxy in
        ScrollView(.horizontal, showsIndicators: false) {
            LazyHStack(spacing: 0) {
                ForEach(0...10, id: \.self) { index in
                    Circle()
                        .frame(width: 100, height: 100)
                        .foregroundStyle(.primary)
                        .id(index)
                        .onTapGesture {
                            print("tap \(index)")
                            withAnimation {
                                activeIndex = index
                            }
                        }
                        .offset(x: (outerProxy.size.width * 0.5 - 100/2))
                }
            }
            /// Don't use padding. Use the offset on each individual element instead.
            //.padding(.horizontal, outerProxy.size.width * 0.5 - 100/2)
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.viewAligned)
        .scrollPosition(id: $activeIndex, anchor: .leading)
        .overlay {
            Circle()
                .stroke(.red, lineWidth: 10)
                .frame(width: 100, height: 100)
        }
    }
}

在本例中我去掉了

ScrollViewReader
,因为由于新的 API,它是多余的。

您也可以使用旧的 API 来使用它。只需像我上面所做的那样删除应用于

LazyVStack
的填充,并使用应用于圆圈的偏移量,然后将
proxy.scrollTo
行更改为:

proxy.scrollTo(index, anchor: .leading)

让我知道这是否适合您!

© www.soinside.com 2019 - 2024. All rights reserved.