水平 ScrollView 在 SwiftUI 中发生变化时垂直弹跳
Horizontal ScrollView bounces vertically in SwiftUI on change
我在 iOS 15 中遇到 ScrollView
的问题。
使用 scrollTo
时,项目会垂直弹跳。
我在 iOS 14 中没有遇到过这个问题。反弹非常随机,没有任何逻辑可言,无法理解它何时会跳跃。
如果我从滚动视图中删除填充,它是固定的,但我需要额外的 space UI 设计者的要求。
此外,尝试使用 .frame
而不是 .padding
,结果相同。
有谁知道如何解决这个问题或者为什么它只在 iOS 15 中发生?
代码:
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader{ proxy in
HStack(spacing: 32){
ForEach(...){ index in
QuestionCell(...)
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture{
withAnimation(.spring()){
selectedIndex = index
}
}
}
}
.padding(.leading)
.padding() // Removing this fixes the bounce bug.
.onChange(of: selectedIndex) { value in
withAnimation(.spring()){
let paramsCount = <SOME MODEL>.count
if value < paramsCount{
proxy.scrollTo(value, anchor: .center)
}else{
proxy.scrollTo(paramsCount - 1, anchor: .center)
}
}
}
}
}
}
问题是 HStack
上的垂直填充。
问题的最小可重现示例
这是最小代码的问题,任何人都可以运行。使用此代码作为参考,看看有什么变化:
struct ContentView: View {
@State private var selectedIndex = 0
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(spacing: 32) {
ForEach(0 ..< 10, id: \.self) { index in
Text("Question cell at index: \(index)")
.background(Color(UIColor.systemBackground))
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture {
withAnimation(.spring()) {
selectedIndex = index
proxy.scrollTo(index, anchor: .center)
}
}
}
}
.padding(.leading)
.padding() // Removing this fixes the bounce bug
}
}
.background(Color.red)
}
}
解决方案
您可以通过 .horizontal
填充从 HStack
移除垂直填充,然后将 .vertical
填充添加到每个 Text
视图。
代码:
struct ContentView: View {
@State private var selectedIndex = 0
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(spacing: 32) {
ForEach(0 ..< 10, id: \.self) { index in
Text("Question cell at index: \(index)")
.background(Color(UIColor.systemBackground))
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture {
withAnimation(.spring()) {
selectedIndex = index
proxy.scrollTo(index, anchor: .center)
}
}
.padding(.vertical) // <- HERE
}
}
.padding(.leading)
.padding(.horizontal) // <- HERE
}
}
.background(Color.red)
}
}
Before
After
在 proxy.scrollTo(index, anchor: ...)
中使用 .bottom
而不是 .center
。
如果我们设置 .top 或 .center 锚点,proxy.scrollTo
动画期间垂直内容偏移会发生变化。它看起来像一些苹果虫。
为避免这种情况,我们应该对齐在滚动过程中导致零偏移的锚点。
对于水平滚动视图,我们应该更改:
- .trailing -> .bottomTrailing
- .center -> .bottom
- .leading -> .bottomLeading
对于垂直:
- .top -> .topTrailing
- .center -> .trailing
- .bottom -> .bottomTrailing
我在 iOS 15 中遇到 ScrollView
的问题。
使用 scrollTo
时,项目会垂直弹跳。
我在 iOS 14 中没有遇到过这个问题。反弹非常随机,没有任何逻辑可言,无法理解它何时会跳跃。
如果我从滚动视图中删除填充,它是固定的,但我需要额外的 space UI 设计者的要求。
此外,尝试使用 .frame
而不是 .padding
,结果相同。
有谁知道如何解决这个问题或者为什么它只在 iOS 15 中发生?
代码:
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader{ proxy in
HStack(spacing: 32){
ForEach(...){ index in
QuestionCell(...)
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture{
withAnimation(.spring()){
selectedIndex = index
}
}
}
}
.padding(.leading)
.padding() // Removing this fixes the bounce bug.
.onChange(of: selectedIndex) { value in
withAnimation(.spring()){
let paramsCount = <SOME MODEL>.count
if value < paramsCount{
proxy.scrollTo(value, anchor: .center)
}else{
proxy.scrollTo(paramsCount - 1, anchor: .center)
}
}
}
}
}
}
问题是 HStack
上的垂直填充。
问题的最小可重现示例
这是最小代码的问题,任何人都可以运行。使用此代码作为参考,看看有什么变化:
struct ContentView: View {
@State private var selectedIndex = 0
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(spacing: 32) {
ForEach(0 ..< 10, id: \.self) { index in
Text("Question cell at index: \(index)")
.background(Color(UIColor.systemBackground))
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture {
withAnimation(.spring()) {
selectedIndex = index
proxy.scrollTo(index, anchor: .center)
}
}
}
}
.padding(.leading)
.padding() // Removing this fixes the bounce bug
}
}
.background(Color.red)
}
}
解决方案
您可以通过 .horizontal
填充从 HStack
移除垂直填充,然后将 .vertical
填充添加到每个 Text
视图。
代码:
struct ContentView: View {
@State private var selectedIndex = 0
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(spacing: 32) {
ForEach(0 ..< 10, id: \.self) { index in
Text("Question cell at index: \(index)")
.background(Color(UIColor.systemBackground))
.scaleEffect(selectedIndex == index ? 1.175 : 1.0)
.onTapGesture {
withAnimation(.spring()) {
selectedIndex = index
proxy.scrollTo(index, anchor: .center)
}
}
.padding(.vertical) // <- HERE
}
}
.padding(.leading)
.padding(.horizontal) // <- HERE
}
}
.background(Color.red)
}
}
Before | After |
---|---|
在 proxy.scrollTo(index, anchor: ...)
中使用 .bottom
而不是 .center
。
如果我们设置 .top 或 .center 锚点,proxy.scrollTo
动画期间垂直内容偏移会发生变化。它看起来像一些苹果虫。
为避免这种情况,我们应该对齐在滚动过程中导致零偏移的锚点。
对于水平滚动视图,我们应该更改:
- .trailing -> .bottomTrailing
- .center -> .bottom
- .leading -> .bottomLeading
对于垂直:
- .top -> .topTrailing
- .center -> .trailing
- .bottom -> .bottomTrailing