Я перехожу с UIKit на SwiftUI и все еще пытаюсь понять некоторые его части, особенно переходы между представлениями.
У меня есть ситуация, когда на экране отображается контроллер представления со списком, скажем, ElementsListViewController()
, и при нажатии на элемент я хочу отобразить модальное окно с пользовательским интерфейсом/анимацией: появится непрозрачное наложение с анимацией альфа-значения, а белый модальный «лист» будет появляться снизу вверх.
Вот как это выглядит:
С UIKit я бы использовал UIViewControllerAnimatedTransitioning
для этого.
Теперь я хотел бы сделать то же самое со SwiftUI, но я потерялся, что делать именно здесь.
У меня пока так:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ElementsList()
}
}
}
struct ElementsList: View {
@State var elements: [String] = (0..<100).map { "Element #\($0)" }
var body: some View {
List(elements, id: \.self) {
Text($0)
.onTapGesture {
// what to do here to display ModalView as I want to?
}
}
.listStyle(PlainListStyle())
}
}
struct ModalView: View {
var body: some View {
ZStack {
Color.black.opacity(0.8)
Color.white
.cornerRadius(20.0)
.padding(.top, 150)
}
.ignoresSafeArea()
}
}
Каков мой лучший вариант здесь? спасибо за помощь
@loremipsum Спасибо за ответ! Я знаю, что мог бы легко сделать это с помощью UIViewControllerRepresentable, но я намерен сделать это на 100% SwiftUI, если это возможно, чтобы понять его как можно лучше!
это невозможно сделать со стандартными ViewModifier
s. Вы можете создать свой собственный, а также пользовательский ViewModifier и Binding<Bool>
, но вы потеряете свайп, особенно свайп с List
. DragGesture
будет мешать перетаскиванию List
или ScrollView
Ну, такой встроенной гибкости нет, скажем, в стандартном .sheet, но ее можно очень быстро реализовать на заказ.
Вот простая демонстрация (Xcode 13.3/iOS 15.4)
Основная часть:
struct ElementsList: View {
// ...
ModalView(isPresented: $isModal) {
List(elements, id: \.self) {
struct ModalView<V: View>: View {
@Binding var isPresented: Bool
// ...
ZStack {
content()
ZStack {
VStack {
if isPresented {
Color.black.opacity(0.8)
.transition(.opacity)
}
}.animation(.easeInOut(duration: 0.25), value: isPresented)
Полный тестовый код в проекте находится здесь
Спасибо @Аспери!
Создайте свой собственный и/или используйте UIViewControllerRepresentable. Это кажется сложнее, чем есть на самом деле, но я бы хотел, чтобы вы знакомы с UIKit, это всего лишь несколько дополнительных строк, чтобы заставить его работать со SwiftUI см. здесь для начала