Spa*_*ard 10 ios swift swiftui
I have seen discussion about this that involve UIKit but nothing recent that includes SwiftUI.
I have a Master-Detail style app that calls for two floating buttons that should be visible at all times in the app.
Settings Button: When tapped will un-hide another overlay with some toggles Add Record Button: When tapped will present a sheet via a @State variable, when tapped again will dismiss the sheet.
If I set the buttons as overlays on the NavigationView they get pushed into the background when the sheet it presented. This isn't particularly surprising but it is not the behaviour that is called for in the design.
First Approach - .overlay on NavigationView()
struct ContentView: View {
@State var addRecordPresented: Bool = false
var body: some View {
NavigationView {
VStack {
SomeView()
AnotherView()
.sheet(isPresented: $addRecordPresented, onDismiss: {self.addRecordPresented = false}) {AddRecordView()}
}
.overlay(NewRecordButton(isOn: $addRecordPresented).onTapGesture{self.addRecordPresented.toggle()}, alignment: .bottomTrailing)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Second Approach - overlay as second UIWindow
I then started again and attempted to create a second UIWindow in SceneDelegate which contained a ViewController hosting the SwiftUI view within UIHostingController, however I had no success trying to override in order to allow both the button to be tappable, but for other taps to be passed through to the window behind the overlay window.
Data flow stuff is removed, this is just trying to present a floating tappable circle that will toggle between green and red when tapped, and has a purple square in the main content view that will present a yellow sheet when tapped. The circle correctly floats on top of the sheet however never responds to taps.
In SceneDelegate:
var window: UIWindow?
var wimdow2: UIWindow2?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
(...)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.windowLevel = .normal
window.makeKeyAndVisible()
let window2 = UIWindow2(windowScene: windowScene)
window2.rootViewController = OverlayViewController()
self.window2 = window2
window2.windowLevel = .normal+1
window2.isHidden = false
}
}
(...)
class UIWindow2: UIWindow {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event)
if hitView != self {
return nil
}
return hitView
}
}
Run Code Online (Sandbox Code Playgroud)
in a ViewController file:
import UIKit
import SwiftUI
class OverlayViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let overlayView = UIHostingController(rootView: NewRecordButton())
addChild(overlayView)
overlayView.view.backgroundColor = UIColor.clear
overlayView.view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
overlayView.view.isUserInteractionEnabled = true
self.view.addSubview(overlayView.view)
overlayView.didMove(toParent: self)
}
}
struct NewRecordButton: View {
@State var color = false
var body: some View {
Circle().foregroundColor(color ? .green : .red).frame(width: 50, height: 50).onTapGesture {
self.color.toggle()
print("tapped circle")
}
}
}
Run Code Online (Sandbox Code Playgroud)
Plain vanilla swiftUI view in the main content window:
import SwiftUI
struct ContentView: View {
@State var show: Bool = false
var body: some View {
NavigationView {
VStack {
Rectangle().frame(width: 100, height: 100).foregroundColor(.purple).onTapGesture {self.show.toggle()}
Text("Tap for Yellow").sheet(isPresented: $show, content: {Color.yellow}
)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Any suggestions or references for how to implement this properly would be greatly appreciated!
从技术上讲这是可能的,但我设法让它发挥作用的方式是脆弱且丑陋的。这个想法是
那是:
UIApplication.shared.windows.first?.addSubview(settingsButton)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
UIApplication.shared.windows.first?.bringSubviewToFront(settingsButton)
}
归档时间: |
|
查看次数: |
3819 次 |
最近记录: |