Я создаю собственную полноэкранную обложку, которую можно перетаскивать жестом, как в приложении подкаста.
Для модификатора перехода с краем в качестве нижнего он использует нижний край родительского представления, поэтому, если родительское представление не игнорирует безопасную область, анимация удаления (т. е. скольжение вниз) «застревает»/«сбивается» внизу. край экрана.
Проблема в том, что я хочу, чтобы элементы полноэкранного покрытия, такие как текст и кнопки, соответствовали безопасной области, за исключением ее фона.
Я не уверен, как это исправить. Каждое отдельное решение по stackoverflow совершенно не имеет значения, поскольку они предлагают использовать модификатор фона, не принимая во внимание использование модификаторов, таких как переход с краем в качестве нижнего.
struct Tabs: View {
@State private var showingCover = false
var body: some View {
ZStack {
TabView {
...
}
if showing {
FullScreenCover(showingCover: $showingCover)
.zIndex(1)
.transition(.move(edge: .bottom))
}
}
.ignoresSafeArea() //I need to set this here so that the bottom edge recognised by the transition modifier would be the very bottom edge of the device.
}
}
struct FullScreenCover: View {
@Binding var showingCover: Bool
@State private var offset: CGFloat = 0.0
var body: some View {
ZStack(alignment: .bottom) {
//Blue color is the background
Color.blue
.ignoresSafeArea()
//Other elements like text must respect safe area
Text("Hello")
}
.offset(y: offset)
.gesture(
DragGesture(minimumDistance: 1)
.onChanged { value in
if value.translation.height > 0 {
withAnimation(.smooth(duration: 0.1)) {
//Drag cover vertically based on drag gesture
offset = value.translation.height
}
}
}
.onEnded { value in
if value.predictedEndTranslation.height < 200 {
withAnimation(.smooth()) {
//Pop cover back fully
offset = 0
}
} else {
withAnimation(.smooth()) {
//Dismiss cover to the bottom of the screen
showingCover = false
offset = 0
}
}
}
)
}
}





Мне до сих пор непонятно, почему вы не можете использовать .fullScreenCover? Жест перетаскивания также можно использовать для этого контента. Вам просто нужно установить фон презентации на Color.clear, чтобы можно было видеть базовый вид.
struct ContentView: View {
@State private var showingCover = false
var body: some View {
TabView {
Button("Show full screen cover") {
showingCover.toggle()
}
}
.fullScreenCover(isPresented: $showingCover) {
FullScreenCover(showingCover: $showingCover)
.presentationBackground(.clear)
}
}
}

Если я не ошибаюсь, .presentationBackground(.clear) требует iOS 16.4 и более поздних версий, но мне нужна поддержка до iOS 16 и более поздних версий. Но ваше решение также справедливо.
И после тестирования вашего решения, одним из основных недостатков является то, что когда вы перетаскиваете обложку ниже безопасной области и пытаетесь перетащить ее в безопасную область в верхней части iPhone, фон обложки «застревает»/«застревает» прямо в месте. граница безопасной зоны.
Решение, к которому я пришел после тестирования различных других решений в течение недели, заключается в чтении вставок безопасной области родительского представления представления вкладок (т. е. в моем случае это ContentView или даже структура приложения, которая также работает), а затем внедрение этого в окружающая среда.
Затем прочитайте вставки безопасной области из среды в представлении FullScreenCover и восстановите в нем заполнение вставок безопасной области.
struct SafeAreaInsetsKey: EnvironmentKey {
static let defaultValue: EdgeInsets = EdgeInsets()
}
extension EnvironmentValues {
var safeAreaInsets: EdgeInsets {
get { self[SafeAreaInsetsKey.self] }
set { self[SafeAreaInsetsKey.self] = newValue }
}
}
var body: some Scene {
WindowGroup {
GeometryReader { geo in
ContentView()
.environment(\.safeAreaInsets, geo.safeAreaInsets)
}
}
}
struct FullScreenCover: View {
@Environment(\.safeAreaInsets) var safeAreaInsets
var body: some View {
ZStack(alignment: .bottom) {
//Blue color is the background
Color.blue
.ignoresSafeArea()
//Other elements like text must respect safe area
VStack {
Text("Hello")
}
.padding(safeAreaInsets)
}
}
}
Я рад представить и другие, более нативные решения.
@SwiftUIEnthusiast Еще одна попытка с
.fullScreenCover. Почему именно вы не можете использовать этот подход?