I have created a button in my UIView but can't figure out why it wont work. The same code works fine in other UIViews. Here is my code. I have tried different combinations of initializing the button with a frame or by using constraints but it makes no difference.
override func viewDidLoad() {
super.viewDidLoad()
let backButton: UIButton = {
let button = UIButton()
button.setTitle("BACK", for: .normal)
button.setTitleColor(Constants.APP_TEXT_COLOR, for: .normal)
button.titleLabel?.font = Constants.APP_HEADER_FONT
button.backgroundColor = .blue
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(pressBackButton(button:)), for: .touchUpInside)
return button
}()
backView.addSubview(backButton)
view.addSubview(backgroundView)
backgroundView.addSubview(webView)
backgroundView.addSubview(backView)
}
and my function
func pressBackButton(button: UIButton) {
print("BUTTON PRESSED")
}
It works fine when i try your code with one change as i don't have backView. So replaced
backView.addSubview(backButton)
with
self.view.addSubview(backButton)
I can see the log present in pressBackButton function on console on pressing the button. Make sure your console view is not disabled. shift+command+C shows the console view.
Related
Here's the code I have:
private struct ShareButton: UIViewRepresentable {
func makeUIView(context: Context) -> UIButton {
let activityViewController = UIActivityViewController(activityItems: [URL(string: "https://www.apple.com/")!], applicationActivities: nil)
let action = UIAction(title: "Share") { _ in UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.rootViewController?.present(activityViewController, animated: false) }
let button = UIButton(primaryAction: action)
activityViewController.popoverPresentationController?.sourceView = button
return button
}
func updateUIView(_ uiView: UIButton, context: Context) { }
}
Basically it's creating a UIButton with a UIAction, inside which there's a UIActivityViewController that set sourceView for the share menu to be the UIButton.
Here's a demo of the issue:
The UIButton is created when the SwiftUI view is created, and set as the sourceView. My guess is that the issue occur because the UIButton is somehow destroyed and recreated due to some SwiftUI mechanism? I can be entirely wrong though. Anyway to solve this?
Or any other way to do share button in a SwiftUI Catalyst Mac app?
"Or any other way to do share button in a SwiftUI Catalyst Mac app?"
You could try this approach, using the extension from:
How to get rid of message " 'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead" with AdMob banner?
public extension UIApplication {
func currentUIWindow() -> UIWindow? {
let connectedScenes = UIApplication.shared.connectedScenes
.filter({
$0.activationState == .foregroundActive})
.compactMap({$0 as? UIWindowScene})
let window = connectedScenes.first?
.windows
.first { $0.isKeyWindow }
return window
}
}
struct ContentView: View {
let holaTxt = "Hola 😀 "
var body: some View {
Button(action: {
let AV = UIActivityViewController(activityItems: [holaTxt], applicationActivities: nil)
UIApplication.shared.currentUIWindow()?.rootViewController?.present(AV, animated: true, completion: nil)
}) {
Text("Share")
}
}
}
Found an elegant solution for creating a share button in a SwiftUI Catalyst Mac app (in fact, all SwiftUI app), see https://github.com/SwiftUI-Plus/ActivityView
I'm currently developing an application using SwiftUI.
When I use a onTapGesture at Form in NavigationView, navigation of Picker the inside doesn't work.
It works but only when I long-press a link like a LongPressGesture.
If I don't use onTapGesture, the navigation of Picker works, as usual, But in that case, I can not close a keyboard when I use TextField choosing numberPad as keyboardType...
How could I solve this problem?
Here is a code:
OnTapGestureTest.swift
import SwiftUI
struct OnTapGestureTest: View{
#State var inputNo:String = ""
#State var selectNo:Int = 0
var body: some View {
NavigationView{
Form{
TextField("InputNo", text: $inputNo)
.keyboardType(.numberPad)
Picker(selection:$selectNo, label: Text("SelectNo")){
Text("0").tag(0)
Text("1").tag(1)
Text("2").tag(2)
Text("3").tag(3)
Text("4").tag(4)
Text("5").tag(5)
}
}
.onTapGesture {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
}
}
UPDATED
I tried to solve my question by referencing here.
*I want to close keyboard only on Tap outside (without handling drags) in iOS 13.0
SceneDelegate.swift
...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
let tapGesture = UITapGestureRecognizer(target: window, action:#selector(UIView.endEditing))
tapGesture.requiresExclusiveTouchType = false
tapGesture.cancelsTouchesInView = false
tapGesture.delegate = self
window?.addGestureRecognizer(tapGesture)
}
...
But it still doesn't work well... Do I need to do some more things? misunderstand the answer?
Xcode: Version 12.0.1
iOS: 13.0
You could add the tap gesture globally, with the help of UIWindow:
extension UIApplication {
func addTapGestureRecognizer() {
guard let window = windows.first else { return }
let tapGesture = UITapGestureRecognizer(target: window, action: #selector(UIView.endEditing))
tapGesture.requiresExclusiveTouchType = false
tapGesture.cancelsTouchesInView = false
tapGesture.delegate = self
window.addGestureRecognizer(tapGesture)
}
}
extension UIApplication: UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
In your main: (The idea: as soon as your app launches, this tapGesture is added to the window)
#main
struct YourApp: App {
...
var body: some Scene {
WindowGroup {
//Your initial view
.onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
}
}
}
This is especially convenient since you don't have to take care of hiding the keyboard ever again inside your views and it's not blocking any of your controls.
Note
This code is from Here
Also, I saw iOS13 - for non SwiftUI Cycle, this would be the equivalent: Here
I am new to swiftUI.I need to create a keyboard extension in swiftui. I just can't find out how to do that. I am searching on internet for whole day but still can't find out how to do that.
Here is some code that I wrote :
struct ContentView: View {
var body: some View {
VStack{
keyboard()
}
}
}
struct keyboard: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIInputViewController {
let inputVC = UIInputViewController()
return inputVC
}
func updateUIViewController(_ uiViewController: UIInputViewController, context: Context) {
print("some text")
}
}
The above code is written in extension folder's keyboardViewController.swift file and not giving me any kind of keyboard display.
IF I write UIKit UIInputController (the file created itself when we create an extension) code in same file then only I can see a keyboard extension appearing.
I want to design keyboard in UIKit Inputviewcontroller type of class and then display it using UIViewControllerRepresentable in swiftui contentview.
Now my question is-> Is this Approach right?? IF yes then please guide me ahead. IF no then please suggest me the right approach.
Thanks in advance!!
Here's my approach using UIHostingController:
When I added a new target "Keyboard" of keyboard extension, XCode automatically generated a class KeyboardViewController:
class KeyboardViewController: UIInputViewController {
// some code
override func viewDidLoad() {
super.viewDidLoad()
self.nextKeyboardButton = UIButton(type: .system)
// some code
}
// some code
}
I added the view through UIHostingController with my keyboard view as the rootView of it. Then added it and its view as children of KeyboardViewController and the view of KeyboardViewController:
class KeyboardViewController: UIInputViewController {
// some code
override func viewDidLoad() {
super.viewDidLoad()
let hostingController = UIHostingController(rootView: KeyboardView(viewController: self))
view.addSubview(hostingController.view)
addChild(hostingController)
self.nextKeyboardButton = UIButton(type: .system)
// some code
}
// some code
}
And my KeyboardView was like:
struct KeyboardView: View {
var viewController: KeyboardViewController
var body: some View {
// some view as you designed
}
}
It worked for me.
In SwiftUI, it seems like the best way to set up an AVPlayerViewController is to use the UIViewControllerRepresentable in a fashion somewhat like this...
struct PlayerViewController: UIViewControllerRepresentable {
var videoURL: URL?
private var player: AVPlayer {
return AVPlayer(url: videoURL!)
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.modalPresentationStyle = .fullScreen
controller.player = player
controller.player?.play()
return controller
}
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
}
}
However from the documentation that the only way to show this controller in a full-screen way is to present it using a sheet.
.sheet(isPresented: $showingDetail) {
PlayerViewController(videoURL: URL(string: "..."))
.edgesIgnoringSafeArea(.all)
}
This doesn't give you a full-screen video with a dismiss button but a sheet modal which can be swiped away instead.
In standard non-SwiftUI Swift, it would seem like the best way would be to present this controller...
let controller = PlayerViewController(videoURL: URL(string: "..."))
self.present(controller, animated: true)
...but SwiftUI doesn't have a self.present as part of it. What would be the best way to present a full-screen video in SwiftUI?
Instead of sheet I would use the solution with ZStack (probably with custom transition if needed), like below
ZStack {
// ... other your content below
if showingDetail { // covers full screen above all
PlayerViewController(videoURL: URL(string: "..."))
.edgesIgnoringSafeArea(.all)
//.transition(AnyTransition.move(edge: .bottom).animation(.default)) // if needed
}
}
i work with Xcode 8 and swift 3.
i have a viewcontroller (Class User:NSViewcontroller) with a button.
This Button has an action:
#IBAction func btnAction(_ sender: Any) {
let popover = NSPopover()
popover.contentViewController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "Popover") as! NSViewController
popover.show(relativeTo: button.bunds , of: button, preferredEdge: .maxX)
}
This button open another view controller as popover.
this popover view controller (Class Popover:NSViewController) do some actions.
now my question is: how can I close the popover viewcontroller from the popover class?
Not sure about the above code but in order to create your PopoverView and dismiss it. Here are the steps:-
1) Create one new View Controller names as PopOverViewController.swift
2) Implement the below method inside that:-
func updatePopOverViewController(_ button: UIButton?, with delegate: AnyObject?) {
guard let button = button else { return }
modalPresentationStyle = .popover
popoverPresentationController?.permittedArrowDirections = [.up]
popoverPresentationController?.backgroundColor = view.backgroundColor
popoverPresentationController?.sourceView = button
popoverPresentationController?.sourceRect = button.bounds
popoverPresentationController?.delegate = OtherViewControllerClass
}
3) Inside your OtherViewControllerClass implement the following code:-
extension OtherViewControllerClass: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
//your code for eg. if you want to change the tint color of our button
}
//When you tap on button it will show the popover and while tapping on yourViewcontroller view it will dismiss the popover accordingly.
#IBAction func buttonClicked(_ sender: UIButton) {
let viewController = PopOverViewController()
viewController.updatePopOverViewController(sender, with: self)
present(viewController, animated: true, completion: nil)
}
}
Well I might be totally guessing here as I have no idea about how your ViewController is written but this should fairly work
self.presentedViewController?.dismiss(animated: true, completion: nil)
The basic thing here is you can access the VC which presented the popover and then call dismiss over it.