Невосприимчивое представление (проблема) в ScrollView, который содержит GeometryReader для определения размера каждого вложенного представления
Представьте себе список задач, в котором вам нужны настраиваемые анимированные флажки для каждой задачи. Поскольку списки, похоже, плохо работают со специальными кнопками, я решил использовать вертикальный ScrollView, который состоит из VStack из массива элементов с помощью ForEach. Для каждой ячейки задачи я установил GeometryReader, чтобы использовать его геометрию для изменения размера фигур, которые я собираюсь использовать для флажков. Проблема в том, что последний элемент в ForEach перестает отвечать на жесты. Если я добавляю еще одну задачу, добавленная задача перестает отвечать. Как я могу это исправить? Я не могу получить GeometryReader из ScrollView, потому что он не дает мне размер ячейки задачи. Есть идеи? Кроме того, если я делаю это неправильно, дайте мне знать, я новичок в Swift. В последний раз я программировал много лет назад.
Это представление, которое использует TaskCell:
struct TaskListView: View {
@ObservedObject var catalog: GoalsCatalog
var body: some View {
NavigationView {
VStack {
ScrollView(.vertical, showsIndicators: true) {
VStack(spacing: 40) {
ForEach(catalog.tasks) { task in
TaskCell(task: task)
.environmentObject(self.catalog)
}
}
.padding([.top, .leading], 20.0)
.frame(maxWidth: .infinity)
.fixedSize(horizontal: false, vertical: true)
}
// Solves ScrollView init resizing issue:
if self.catalog.tasks.count == 0 {
Spacer()
}
Button(action: {
self.catalog.addTaskByName(name: "New Task")
}) {
Text("New Task")
}
.padding(.bottom, 8.0)
.navigationBarTitle("Title")
}
}
}
}
Это TaskCell (в процессе):
struct TaskCell: View {
var task: GoalsSystem.Task
@EnvironmentObject var catalog: GoalsCatalog
let generator = UIImpactFeedbackGenerator()
var body: some View {
GeometryReader { geometry in
self.body(for: geometry.size)
}
}
func body(for size: CGSize) -> some View {
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 1)
.fill(self.completedLongPress ? Color.blue : Color.white)
HStack(spacing: 20) {
Button(action: {
print("Click")
self.generator.impactOccurred(intensity: 0.5)
self.catalog.toggleTaskCompletition(of: self.task)
// TODO: - LAST task added can't be toggled as completed. Why?
}) {
ZStack {
RoundedRectangle(cornerRadius: checkBoxCornerRadius)
.fill(Color.gray)
.aspectRatio(1, contentMode: .fit)
RoundedRectangle(cornerRadius: checkBoxCornerRadius)
.stroke(lineWidth: checkBoxLineWidth)
.aspectRatio(1, contentMode: .fit)
}.frame(width: size.width/20, height: size.width/10, alignment: .center)
}
VStack(alignment: .leading) {
Text(task.taskName).strikethrough(task.isComplete)
Text("Details")
.font(.subheadline)
.foregroundColor(Color.gray)
}
.gesture(self.pressToSelect())
.onTapGesture {
self.catalog.toggleTaskCompletition(of: self.task)
}
}
.fixedSize(horizontal: true, vertical: false)
.opacity(task.isComplete ? taskOpacityInactive : taskOpacityActive)
.scaleEffect(self.isDetectingLongPress ? 1.05 : (self.completedLongPress ? 1.1 : 1))
}
}
@GestureState private var isDetectingLongPress = false
@State private var completedLongPress = false
private func pressToSelect() -> some Gesture {
LongPressGesture(minimumDuration: 0.3, maximumDistance: 10)
.updating($isDetectingLongPress) { currentState, gestureState, transaction in
gestureState = currentState
transaction.animation = Animation.easeIn(duration: 0.5)
}
.onEnded { finished in
self.generator.impactOccurred(intensity: 0.5)
self.completedLongPress = true
}
}
// MARK: - Drawing constants
let checkBoxCornerRadius: CGFloat = 7
let checkBoxLineWidth: CGFloat = 2
let taskOpacityActive: Double = 1
let taskOpacityInactive: Double = 0.5
let longPressDuration: Double = 3
let longPressMaximumDistance: CGFloat = 10
}