У меня есть базовое представление прокрутки в SwiftUI со штабелируемыми карточками. Карты можно переключать, проводя по ним. Иногда прокрутку в представлении прокрутки можно принять за перетаскивание в перетаскиваемом представлении. В этом случае верхняя карта перетаскивается в другое место на экране, но onEnded
не срабатывает, и карта остается в этом положении, не возвращаясь обратно в стопку.
Как я могу исправить проблему, из-за которой прокрутка в представлении прокрутки ошибочно принимается за перетаскивание в этом дополнительном представлении?
import SwiftUI
struct tetfqwe: View {
@State var cards: [String] = ["1", "2", "3", "4", "5"]
@State var offset: CGSize = .zero
var body: some View {
ScrollView {
Color.blue.frame(height: 200)
LazyVStack {
ZStack {
ForEach(cards.indices, id: \.self) { index in
Color.red.frame(width: 120, height: 90).cornerRadius(15, corners: .allCorners)
.overlay(content: {
RoundedRectangle(cornerRadius: 15)
.stroke(.black, lineWidth: 1.0)
})
.overlay(content: {
Text("\(index)")
})
.onTapGesture {
UIImpactFeedbackGenerator(style: .light).impactOccurred()
}
.offset(x: Double(((cards.count - 1) - index) * 3))
.offset(x: index == (cards.count - 1) ? offset.width : 0.0, y: index == (cards.count - 1) ? offset.height : 0.0)
.highPriorityGesture(DragGesture()
.onChanged({ value in
if cards.count > 1 {
offset = value.translation
}
})
.onEnded({ value in
if cards.count > 1 {
if abs(value.translation.width) > 45.0 {
ended()
} else {
withAnimation(.bouncy(duration: 0.3)){
offset = .zero
}
}
}
})
)
}
}
}
Color.orange.frame(height: 1000).padding(.top, 100)
Color.green.frame(height: 1000)
Color.gray.frame(height: 1000)
}
}
func ended(){
withAnimation(.bouncy(duration: 0.3)){
let element = cards.removeLast()
cards.insert(element, at: 0)
offset = .zero
}
}
}
#Preview {
tetfqwe()
}
@udi, это не помогло, но спасибо за идею.
Сделайте это в верхней части вашей структуры:
struct tetfqwe: View {
@State var cards: [String] = ["1", "2", "3", "4", "5"]
@State var offset: CGSize = .zero
@State var shouldScroll: Bool // add this to your code
var axes: Axis.Set { // add this to your code
return shouldScroll ? .vertical : []
}
И внизу сделайте следующее:
.highPriorityGesture(DragGesture()
.onChanged({ value in
shouldScroll = false // add this to your code
if cards.count > 1 {
offset = value.translation
}
})
.onEnded({ value in
shouldScroll = true // add this to your code
if cards.count > 1 {
Это решение просто отключает элемент прокрутки во время действия перетаскивания «.onChanged» и повторно включает его, когда жест перетаскивания «onEnded» заканчивается.
Спасибо, это должно сработать. Возможно, есть более простое решение, потому что в моем проекте есть десятки представлений прокрутки, которые могут содержать это подпредставление. Кроме того, у этого подпредставления карточек есть 3-4 родителя, прежде чем вы перейдете к представлению с прокруткой.
@AhmedZaidan Это довольно простое решение. Если в вашем проекте есть десятки представлений прокрутки, содержащих это, создайте еще один View
, который обертывает эту функциональность. Это не значит, что вам нужно копировать и вставлять десятки раз.
попробуйте
simultaneousGesture
вместоhighPriorityGesture