У меня есть собственный вид, в котором есть 3 страницы: синяя, красная и зеленая. Каждая страница занимает всю ширину экрана, и для перемещения между ними я использую жест перетаскивания по краю. Исходный вид — центральный, красный.
Если я перейду на синюю или зеленую страницы и либо: полностью открою лист, либо открою клавиатуру, то красная средняя страница больше не будет доступна для кликов. Однако левая и правая страницы по-прежнему доступны для кликов.
Почему при открытии листа или использовании клавиатуры центральная красная страница становится недоступной для щелчка? Удаление всех игнорируемых безопасных областей решает проблему, но они мне нужны.
Размещение стека навигации в самом верху представления также исправляет ситуацию, но я этого не хочу. Удаление всех игнорируемых безопасных областей из стека навигации также исправляет это, но они мне нужны. Очень странное поведение: если отображается состояние неисправности клавиатуры и вы проводите пальцем по центральной странице, пока отображается клавиатура, центральная страница снова становится доступной для щелчка.
Чтобы воспроизвести: край Swift справа -> сфокусировать текстовое поле -> проведите по краю назад -> кнопка не должна быть кликабельной (дефект)
Код можно копировать и вставлять.
import SwiftUI
struct MainView: View {
@Environment(\.colorScheme) var colorScheme
@State var offset: CGFloat = 0
@State var option: Int = 2
@State var lastStoredOffset: CGFloat = 0
@GestureState var gestureOffset: CGFloat = 0
@State var scale: CGFloat = 0.7
@State var content: Bool = false
@State var text = ""
var body: some View {
HStack(spacing: 0){
// PAGE ONE
ZStack {
Color.blue
.frame(width: widthOrHeight(width: true))
.scaleEffect(scale)
}
.frame(width: widthOrHeight(width: true))
.ignoresSafeArea()
// DIVIDER
Color.blue.ignoresSafeArea().frame(width: 13)
//PAGE 2 WITH DEFECT
NavigationStack {
ZStack {
Color.red
Button(action: {
}, label: {
Text("Button").font(.title)
})
}
.ignoresSafeArea()
}
.frame(width: widthOrHeight(width: true))
.ignoresSafeArea()
//DIVIDER
Color.blue.ignoresSafeArea().frame(width: 13)
//PAGE 3
ZStack {
Color.green
TextField("insert", text: $text)
}
.frame(width: widthOrHeight(width: true))
.ignoresSafeArea()
}
.offset(x: offset)
.simultaneousGesture (
DragGesture()
.onChanged({ value in
let width = widthOrHeight(width: true)
let width2 = width * 2
if option == 2 {
if (value.startLocation.x >= (width + 13) && value.startLocation.x <= (width + 28)) || (value.startLocation.x >= (width2 - 2.0) && value.startLocation.x <= (width2 + 13)) {
offset = value.translation.width + lastStoredOffset
}
} else if option == 1 {
if value.translation.width < 0 {
offset = value.translation.width + lastStoredOffset
}
} else {
if value.translation.width > 0 {
if value.startLocation.x >= (width + 13) && value.startLocation.x <= (width + 28.0) {
offset = value.translation.width + lastStoredOffset
}
}
}
let ratio = (abs(offset) / width) * 0.3
scale = 0.7 + min(0.3, max(0.0, ratio))
})
.onEnded({ value in
let width = widthOrHeight(width: true)
if option == 1 {
if offset < (width * 0.6) || value.velocity.width < -400.0 {
withAnimation(.easeInOut(duration: 0.15)){
offset = 0
scale = 0.7
}
lastStoredOffset = 0
option = 2
} else {
withAnimation(.easeInOut(duration: 0.15)){
offset = width + 13
scale = 1.0
}
lastStoredOffset = width + 13
}
} else if option == 2 {
let leftstart: Bool = (abs(value.startLocation.x - width) < 100.0)
if (offset > (width * 0.4) || value.velocity.width > 400.0) && leftstart {
withAnimation(.easeInOut(duration: 0.15)){
offset = width + 13
scale = 1.0
}
lastStoredOffset = width + 13
option = 1
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
} else if (offset < -(width * 0.4) || value.velocity.width < -400.0) && !leftstart {
withAnimation(.easeInOut(duration: 0.15)){
offset = -width - 13
scale = 1.0
}
lastStoredOffset = -width - 13
option = 3
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
} else {
withAnimation(.easeInOut(duration: 0.15)){
offset = 0
scale = 0.7
}
lastStoredOffset = 0
}
} else {
let isEdge: Bool = value.startLocation.x >= (width + 13) && value.startLocation.x <= (width + 28.0)
if offset > -(width * 0.6) || (value.velocity.width > 400.0 && isEdge) {
withAnimation(.easeInOut(duration: 0.15)){
offset = 0
scale = 0.7
}
lastStoredOffset = 0
option = 2
} else {
withAnimation(.easeInOut(duration: 0.15)){
offset = -width - 13
scale = 1.0
}
lastStoredOffset = -width - 13
}
}
})
)
}
}
func widthOrHeight(width: Bool) -> CGFloat {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
if width {
return window?.screen.bounds.width ?? 0
} else {
return window?.screen.bounds.height ?? 0
}
}
#Preview {
MainView()
}
func top_Inset() -> CGFloat {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
return window?.safeAreaInsets.top ?? 0
}
func bottom_Inset() -> CGFloat {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
return window?.safeAreaInsets.bottom ?? 0
}
Решение, которое я нашел, заключалось в применении .zIndex(1)
к первой и третьей страницам, а .zIndex(500)
к средней странице. Похоже, что клавиатура влияет на безопасную область, поэтому сочетание NavigationStacks и IgnoreSafeAreas может вызвать проблемы.