I want to delay the sheet presentation via shouldPresentEditExpense
. The reason is to show a selection animation of a cell.
The selectable effect takes place via ViewModifier.
overlay { isSelectedItem == item) ? Color.black.opacity(0.2) : Color.clear }
I am pretty sure that there is a better way to achieve this effect.
The view
VStack(spacing: 15) {
ForEach(expensesVM.lastExpenses(limit: Constants.maximumNumberOfExpenses)) { expense in
ExpenseCellView(expense: expense)
.selectableCell(selectedItem: $selectedItem)
.listRowSeparator(.hidden)
.onTapGesture {
selectedItem = expense
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
shouldPresentEditExpense = true
}
}
.animation(.easeOut, value: selectedItem)
}
}
The ViewModifier
//MARK: - Selectable Cell ViewModifier
struct ExpenseSelectableCell: ViewModifier {
@Binding var selectedItem: Expense?
var expense: Expense
func body(content: Content) -> some View {
content
.overlay {
Color.black.opacity(isSelected() ? 0.2 : 0)
}
}
func isSelected() -> Bool {
guard let selectedItem else { return false }
return selectedItem.id == expense.id
}
}
extension ExpenseCellView {
func selectableCell(selectedItem: Binding<Expense?>) -> some View {
self.modifier(ExpenseSelectableCell(selectedItem: selectedItem, expense: self.expense))
}
}
Use withAnimation
to animate the selection. You can pass a completionHandler
to that.
.onTapGesture {
withAnimation {
selectedItem = expense
} completion: {
shouldPresentEditExpense = true
}
}