Я работаю над ячейкой SwiftUI List
, которая может расширяться / уменьшаться, что очень просто можно увидеть во многих контекстах. Что-то вроде следующего (следующее реализовано в UIKit
):

Если честно, я изо всех сил пытаюсь реализовать то же самое в SwiftUI. Я попробовал пару подходов:
1) Первый подход: условно включить нижнюю часть ячейки:
import SwiftUI
struct Approach1: View {
@State private var selectedIndex = -1
var body: some View {
List {
ForEach(0...20, id: \.self) { idx in
Cell(isExpanded: self.selectedIndex == idx)
.onTapGesture {
withAnimation {
self.selectedIndex = (self.selectedIndex == idx) ? -1 : idx
}
}
}
}
}
}
private struct Cell: View {
let isExpanded: Bool
var body: some View {
VStack(alignment: .leading) {
Text("Hello World")
.animation(nil)
if isExpanded {
VStack {
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
}
}
}
}
}
struct Approach1_Previews: PreviewProvider {
static var previews: some View {
Approach1()
}
}
В этом случае, однако, SwiftUI не будет анимировать расширение ячейки, это просто анимирует нижний контент, который появляется / исчезает, и результат действительно странный (я замедлил анимацию, чтобы вы видели):

2) Второй подход: создать две версии ячейки:
import SwiftUI
struct Approach2: View {
@State private var selectedIndex = -1
var body: some View {
List {
ForEach(0...20, id: \.self) { idx in
Group {
if self.selectedIndex == idx {
ExpandedCell()
.onTapGesture {
self.selectedIndex = -1
}
} else {
Cell()
.onTapGesture {
self.selectedIndex = idx
}
}
}
}
}
}
}
private struct Cell: View {
var body: some View {
Text("Hello world")
}
}
private struct ExpandedCell: View {
var body: some View {
VStack(alignment: .leading) {
Cell()
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
Text("Lorem ipsum")
}
}
}
struct Approach2_Previews: PreviewProvider {
static var previews: some View {
Approach2()
}
}
Это кажется правильным способом сделать то, что я хочу. Это действительно близко к тому, что я хотел бы получить:

К сожалению, есть странный сбой, который я не могу исправить, когда нажимаю на ячейку над расширенной ячейкой:

Вы можете мне помочь? Спасибо.