У меня возникла проблема с iOS 26 и использованием «сквозного» UIWindow (он используется для глобального наложения, например, показа уведомлений в приложении).
Код работал нормально в iOS 18, но что-то (очевидно) изменилось в iOS 26. Мое представление SwiftUI (в данном случае кнопка для MRE) не получает касание в iOS 26, но оно есть в iOS 18 (вы можете попробовать запустить MRE в симуляторе с iOS 18 и iOS 26 для сравнения).
MRE:
import SwiftUI
struct RootView: View {
@ViewBuilder let content: Content
@State private var properties = UniversalOverlayProperties()
var body: some View {
content
.environment(properties)
.onAppear {
if let windowScene = (UIApplication.shared.connectedScenes.first as? UIWindowScene),
properties.window == nil {
let window = PassThroughWindow(windowScene: windowScene)
window.isHidden = false
window.isUserInteractionEnabled = true
let rootViewController = UIHostingController(rootView: UniversalOverlayViews().environment(properties))
rootViewController.view.backgroundColor = .clear
window.rootViewController = rootViewController
properties.window = window
}
}
}
}
fileprivate struct UniversalOverlayModifier: ViewModifier {
let animation: Animation?
@Binding var show: Bool
@ViewBuilder let viewContent: ViewContent
// Local View properties
@Environment(UniversalOverlayProperties.self) private var properties
@State private var viewID: String?
func body(content: Content) -> some View {
content
.onChange(of: show, initial: true) {
if show {
addView()
} else {
removeView()
}
}
}
private func addView() {
if properties.window != nil,
viewID == nil {
viewID = UUID().uuidString
withAnimation(animation) {
properties.views.append(.init(id: viewID!, view: .init(viewContent)))
}
}
}
private func removeView() {
if let viewID {
withAnimation(animation) {
properties.views.removeAll(where: { $0.id == viewID })
}
self.viewID = nil
}
}
}
extension View {
func universalOverlay(
animation: Animation? = nil,
show: Binding,
@ViewBuilder content: () -> Content
) -> some View {
self
.modifier(UniversalOverlayModifier(animation: animation, show: show, viewContent: content))
}
}
@Observable
fileprivate final class UniversalOverlayProperties {
var window: UIWindow?
var views = [OverlayView]()
struct OverlayView: Identifiable {
var id = UUID().uuidString
var view: AnyView
}
}
fileprivate struct UniversalOverlayViews: View {
@Environment(UniversalOverlayProperties.self) private var properties
var body: some View {
Button("Tap") {
print("Tapped") // Prints in iOS 18 but not in iOS 26
}
}
}
class PassThroughWindow: UIWindow {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let hitView = super.hitTest(point, with: event),
let rootView = rootViewController?.view else { return nil }
// in iOS 26 rootView.subviews.count is 0
// in iOS 18 rootView.subiews.count is the actual number
for subview in rootView.subviews.reversed() {
// Finding if any of rootviews is receiving hit test
let pointInSubview = subview.convert(point, from: rootView)
if subview.hitTest(pointInSubview, with: event) != nil {
return hitView
}
}
return nil
}
}
struct ContentViewPreview: View {
@State private var show = false
var body: some View {
NavigationStack {
List {
}
.navigationTitle("Universal overlay")
}
.universalOverlay(animation: .easeInOut(duration: 1), show: $show) {
EmptyView()
}
}
}
#Preview {
RootView {
ContentViewPreview()
}
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... -in-ios-26
Сквозной UIWindow с использованием SwiftUI в iOS 26 ⇐ IOS
Программируем под IOS
-
Anonymous
1764684552
Anonymous
У меня возникла проблема с iOS 26 и использованием «сквозного» UIWindow (он используется для глобального наложения, например, показа уведомлений в приложении).
Код работал нормально в iOS 18, но что-то (очевидно) изменилось в iOS 26. Мое представление SwiftUI (в данном случае кнопка для MRE) не получает касание в iOS 26, но оно есть в iOS 18 (вы можете попробовать запустить MRE в симуляторе с iOS 18 и iOS 26 для сравнения).
MRE:
import SwiftUI
struct RootView: View {
@ViewBuilder let content: Content
@State private var properties = UniversalOverlayProperties()
var body: some View {
content
.environment(properties)
.onAppear {
if let windowScene = (UIApplication.shared.connectedScenes.first as? UIWindowScene),
properties.window == nil {
let window = PassThroughWindow(windowScene: windowScene)
window.isHidden = false
window.isUserInteractionEnabled = true
let rootViewController = UIHostingController(rootView: UniversalOverlayViews().environment(properties))
rootViewController.view.backgroundColor = .clear
window.rootViewController = rootViewController
properties.window = window
}
}
}
}
fileprivate struct UniversalOverlayModifier: ViewModifier {
let animation: Animation?
@Binding var show: Bool
@ViewBuilder let viewContent: ViewContent
// Local View properties
@Environment(UniversalOverlayProperties.self) private var properties
@State private var viewID: String?
func body(content: Content) -> some View {
content
.onChange(of: show, initial: true) {
if show {
addView()
} else {
removeView()
}
}
}
private func addView() {
if properties.window != nil,
viewID == nil {
viewID = UUID().uuidString
withAnimation(animation) {
properties.views.append(.init(id: viewID!, view: .init(viewContent)))
}
}
}
private func removeView() {
if let viewID {
withAnimation(animation) {
properties.views.removeAll(where: { $0.id == viewID })
}
self.viewID = nil
}
}
}
extension View {
func universalOverlay(
animation: Animation? = nil,
show: Binding,
@ViewBuilder content: () -> Content
) -> some View {
self
.modifier(UniversalOverlayModifier(animation: animation, show: show, viewContent: content))
}
}
@Observable
fileprivate final class UniversalOverlayProperties {
var window: UIWindow?
var views = [OverlayView]()
struct OverlayView: Identifiable {
var id = UUID().uuidString
var view: AnyView
}
}
fileprivate struct UniversalOverlayViews: View {
@Environment(UniversalOverlayProperties.self) private var properties
var body: some View {
Button("Tap") {
print("Tapped") // Prints in iOS 18 but not in iOS 26
}
}
}
class PassThroughWindow: UIWindow {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let hitView = super.hitTest(point, with: event),
let rootView = rootViewController?.view else { return nil }
// in iOS 26 rootView.subviews.count is 0
// in iOS 18 rootView.subiews.count is the actual number
for subview in rootView.subviews.reversed() {
// Finding if any of rootviews is receiving hit test
let pointInSubview = subview.convert(point, from: rootView)
if subview.hitTest(pointInSubview, with: event) != nil {
return hitView
}
}
return nil
}
}
struct ContentViewPreview: View {
@State private var show = false
var body: some View {
NavigationStack {
List {
}
.navigationTitle("Universal overlay")
}
.universalOverlay(animation: .easeInOut(duration: 1), show: $show) {
EmptyView()
}
}
}
#Preview {
RootView {
ContentViewPreview()
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79768526/passthrough-uiwindow-using-swiftui-in-ios-26[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия