Я создаю собственную полноэкранную обложку, которую можно перетаскивать жестом, как в приложении подкаста.
Для модификатора перехода с краем в качестве нижнего он использует нижний край родительского представления, поэтому, если родительское представление не игнорирует безопасную область, анимация удаления (т. е. скольжение вниз) «застревает»/«сбивается» внизу. край экрана.
Проблема в том, что я хочу, чтобы элементы полноэкранного покрытия, такие как текст и кнопки, соответствовали безопасной области, за исключением ее фона.
Я не уверен, как это исправить. Каждое отдельное решение по 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
. Почему именно вы не можете использовать этот подход?