SwiftUI ScrollView ScrollPosition не обновляется при автопрокруткеIOS

Программируем под IOS
Ответить
Anonymous
 SwiftUI ScrollView ScrollPosition не обновляется при автопрокрутке

Сообщение Anonymous »

Следующий код не может обновить ScrollPosition в SwiftUI ScrollView, когда пользователь выполняет автоматическую прокрутку, т. е. проводит пальцем для прокрутки и немедленно поднимает палец. Пока представление прокрутки продолжает прокручиваться до тех пор, пока оно не замедлится и не остановится при поднятии пальца, элемент ScrollPosition в это время не обновляется. Я так и не смог понять, почему это происходит.
import SwiftUI
import UIKit

struct ScrubberConfig2 {
var count:Int
var majorTickInterval:Int
var spacing:CGFloat
let labelFormatter: ((Int) -> String)?

init(count: Int, majorTickInterval: Int, spacing: CGFloat, labelFormatter: ((Int) -> String)? = nil) {
self.count = count
self.majorTickInterval = majorTickInterval
self.spacing = spacing
self.labelFormatter = labelFormatter
}
}

struct VerticalScrubber2: View {
var config: ScrubberConfig2
@Binding var value: Int

let tickHeight: CGFloat = 5 // 👈 added

@State private var isUserInteracting: Bool = false // New state to track user interaction

@State private var isScrollPositionSet = false // 👈 added
@State private var scrollPosition:Int?

var body: some View {
GeometryReader { geometry in
let verticalPadding = (geometry.size.height - tickHeight) / 2

ZStack(alignment: .trailing) {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: config.spacing) {
ForEach(0...config.count, id: \.self) { index in
horizontalTickMark(for: index)
.frame(height: tickHeight)
.id(index)
}
}
.frame(width: 80)
.scrollTargetLayout()
}
.defaultScrollAnchor(.center)
.scrollTargetBehavior(.viewAligned)
.scrollPosition(id: $scrollPosition, anchor: .center)
.contentMargins(.vertical, verticalPadding)

Capsule()
.frame(width: 32, height: 3)
.foregroundColor(.accentColor)
.shadow(color: .accentColor.opacity(0.3), radius: 3, x: 0, y: 1)
}
.frame(width: 100)
.onAppear {
scrollPosition = value
}
.onChange(of: value, { oldValue, newValue in
if scrollPosition != newValue, !isUserInteracting {
print("📥 Value changed: \(oldValue) → \(newValue)")
scrollPosition = newValue
}
})
.onChange(of: scrollPosition, initial: true, { oldValue, newValue in
if let newValue = newValue, value != newValue, isUserInteracting {
print("👆 ScrollPosition changed: \(oldValue ?? -1) → \(newValue)")
value = newValue
}
})
.onScrollPhaseChange { oldPhase, newPhase in
if newPhase == .interacting {
isUserInteracting = true
} else {
isUserInteracting = false
}
}
}
}

private func horizontalTickMark(for index: Int) -> some View {
let isMajorTick = index % config.majorTickInterval == 0

return HStack(spacing: 8) {
Rectangle()
.fill(isMajorTick ? Color.accentColor : Color.gray.opacity(0.5))
.frame(width: isMajorTick ? 24 : 12, height: isMajorTick ? 2 : 1)

if isMajorTick {
Text(labelText(for: index))
.font(.system(size: 12, weight: .medium))
.foregroundColor(.primary)
.fixedSize()
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.trailing, 8)
}

private func labelText(for index: Int) -> String {
if let formatter = config.labelFormatter {
return formatter(index)
} else {
// Default: show index / steps * 5
let tickValue = index
return "\(tickValue)"
}
}
}

struct VerticalScrubberPreview2: View {
@State private var value: Int = 0
private let config = ScrubberConfig2(count: 100, majorTickInterval: 5, spacing: 5)

var body: some View {
Text("Vertical Scrubber (0–100 in steps of 5)")
.font(.title2)
.padding()

HStack(spacing: 30) {
VerticalScrubber2(config: config, value: $value)
.frame(width:120, height: 300)
.background(Color(.systemBackground))
.border(Color.gray.opacity(0.3))

VStack {
Text("Current Value:")
.font(.headline)
Text("\(value)")
.font(.system(size: 36, weight: .bold))
.padding()
}

Spacer()
}
.padding()
}
}

#Preview {
VerticalScrubberPreview2()
}



Подробнее здесь: https://stackoverflow.com/questions/798 ... autoscroll
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»