Searchbar cancel button not visible only on iPad - swift

First I want to say I didn't find any good answer about it in Swift. I created search bar. On button click it shows and on cancel it hides the searchbar. It is working properly, cancel button is visible on all iPhones but for some reason not on iPad. What should cause this?
That is how I create the searchbar:
//Create searchbar
func createSearchBar(){
searchBar.showsCancelButton = true
searchBar.tintColor = UIColor(red:0.184, green:0.996, blue:0.855, alpha:1.00)
searchBar.placeholder = "Search brands"
searchBar.delegate = self
searchBar.hidden = false
searchBar.alpha = 0
navigationItem.titleView = searchBar
navigationItem.setLeftBarButtonItem(menuButton, animated: true)
navigationItem.setRightBarButtonItem(searchButtton, animated: true)
UIView.animateWithDuration(0.5, animations: {
self.searchBar.alpha = 1
}, completion: { finished in
self.searchBar.becomeFirstResponder()
})
}

Faced the same one of my project. I've posted on apple forum and lot of developers commented as a xcode bug. So I added the cancel button manually for ipad views
func configureCancelBarButton() {
let cancelButton = UIBarButtonItem()
cancelButton.image = UIImage(named: "cancelButton")
cancelButton.action = #selector(viewController.ipadCancelButton(_:))
cancelButton.target = self
self.navigationItem.setRightBarButtonItem(cancelButton, animated: true)
}
And I previously posted an answer about this question. Check that too. :)

https://developer.apple.com/documentation/uikit/uisearchbar/1624283-showscancelbutton
The value of this property is ignored, and no cancel button is displayed, for apps running on iPad.
Apple add that in documents!

The UISearchbar's cancel button will work in iPads if you are NOT using the UISearchbar as NavigationBarItem.

Related

Swift | UIViewController not showing as PopUp but Fullscreen

So i have a viewcontroller which is basically an alert window which is supposed to be a popup and be dismissed by the tap on outside its frame.
But whenever i call that VC, it is always displayed as fullscreen and not as a pop up window.
I have tried a couple of ways to do this, namely as mentioned below.
if let exp : String = expiredVehicles[i] {
expiredVehicleNumber = expiredVehicles[i]
let popUpVC = SubscriptionExpired()
popUpVC.modalTransitionStyle = .crossDissolve
popUpVC.modalPresentationStyle = .popover // also tried other presentation styles but none work and it is still fullscreen
popUpVC.view.backgroundColor = UIColor.white.withAlphaComponent(0.8)
self.present(popUpVC, animated: true, completion: nil)
}
in case anyone need to see the definition of that VC, i will be glad to share it
i feel i should mention that the VC to be displayed as a popup is inheriting UIViewController
Any insight that might help would be great.
Thanks for the input
One potential way is to add a tap gesture recognizer to your View, which dismisses the VC.
But this will only be helpful if this popup has read-only info and doesn't require any further action from the user.
func addTapRecognizer(){
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap))
self.view.addGestureRecognizer(tap)
}
#objc func handleTap(){
// dismiss the VC here
}
}
You can call following method to show popup:
let popupVC = SubscriptionExpired()
popupVC.modalPresentationStyle = .overCurrentContext
self.addChild(popupVC)
popupVC.view.frame = self.view.frame
self.view.addSubview(popupVC.view)
popupVC.didMove(toParent: self)
}
Then, for removing that popup you can use:
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0
}, completion: { (finished) in
if finished {
self.view.removeFromSuperview()
}
})
In that case I have a button inside popup and whenever that button pressed above method triggers. Can you please try it? I can edit my answer according to your needs.
You need to implement this in you presenting view controller:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .none
}
UIPopoverPresentationController displaying popover as full screen

UITapGestureRecognizer Crashes App..?

I am using image views to display users' friends lists. The user should be able to tap on a friend's icon and be taken to another screen. The code I've written works perfectly on the Xcode simulator. However, when running on a device, the app crashes every single time as soon as I tap an icon.
I really am unsure where to even start debugging this, even after tons of google-ing. Any advice/ help is appreciated.
I have read that my specific error potentially has something to do with memory allocation(?) but still unsure where to start/ what to do. When I check my device logs, the exception type shows this: Exception Type: EXC_BAD_ACCESS (SIGSEGV). I've followed tutorials on finding zombies and it did not help. Thank you.
I'm not really sure what code to post, but since you'll probably want to make sure I am setting up the icons correctly: (i've deleted some code to keep it simple as possible; this is running in a loop to create x amount of icons)
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.image = image!
iv.tag = j
iv.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.iconTapped))
iv.isUserInteractionEnabled = true
iv.addGestureRecognizer(tapGestureRecognizer)
iconTapped function:
func iconTapped(gestureRecognizer: UITapGestureRecognizer, _ sender: AnyObject) {
print("TAPPED NUMBER: \(gestureRecognizer.view?.tag)")
tappedIcon = CurrentSixFriendsList[(gestureRecognizer.view?.tag)!]
let nextVC = ConfirmOpponentViewController()
nextVC.chosenOpponent = tappedIcon
navigationController?.pushViewController(nextVC, animated: true)
}
UPDATE:
I've commented out all code on nextVC and all code in iconTapped except for a print statement. The app still crashes on device only when I tap any friend icon.
func iconTapped(gestureRecognizer: UITapGestureRecognizer, _ sender: AnyObject) {
print("tapped")
}
SECOND UPDATE:
so i commented out all the code for rendering the image views and I hardcoded an image view. (just one image view) with a static image from my project. the image view displays and the app crashes even when i tap on this imageView. why is it acting so strange!? i'm going crazy...
I added this code in VDL just to experiment:
let iv = UIImageView()
iv.isUserInteractionEnabled = true
iv.translatesAutoresizingMaskIntoConstraints = false
iv.image = #imageLiteral(resourceName: "settings icon")
view.addSubview(iv)
iv.widthAnchor.constraint(equalToConstant: 100).isActive = true
iv.heightAnchor.constraint(equalToConstant: 100).isActive = true
iv.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
iv.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iconTapped))
iv.addGestureRecognizer(tapGestureRecognizer)
Finally, found out why it was crashing.
Your tapped function:
func iconTapped(gestureRecognizer: UITapGestureRecognizer, _ sender: AnyObject) {
print("tapped")
}
should be like this:
func iconTapped(gesture: UITapGestureRecognizer) {
// To get the sender's tag, do this:
print(gesture.view.tag)
}
Also adjust the #selector to the right function.
When setting a selector to UITapGestureRecognizer, the recognizer object will call the selector with only the sender, and you can not add another argument to that function.
So, the root cause of the crash is because you are trying to fit a method with one argument (which is what the gesture sends out) into a method with two arguments. This crash was very interesting because it worked all right on the simulator but only crashed in an actual device. I guess it was because the simulator and the device handle functions with extra parameters differently? (simulator ignores it vs. device crashes). If you find anything deeper as to why exactly this was happening, I would love to know.
Most probly your CurrentSixFriendsList doesnot have value of gestureRecognizer.view?.tag)!.But a breakpoint before this line
tappedIcon = CurrentSixFriendsList[(gestureRecognizer.view?.tag)!]
Even then if you dont get an error then install crashlytics.This is a tool which will tell your crash issue.
Replace your tap gesture code & From swift 3.x you need to use #selector
let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(dismissKeyboard))
self.view.addGestureRecognizer(tapGesture)
#objc func dismissKeyboard(gesture: UITapGestureRecognizer) {
view.endEditing(true)
}

Swift 3 Popover Dim Background

I have read multiple places with suggestions on how to accomplish this. I went with adding a UI view in the background and setting it to disable and then after showing the popover, setting the view to enable.
As you can see it looks to work nicely:
But I do have two problems. The first one is once the popover is presented, you can tap anywhere on the background to dismiss the popover. Is there anywhere to block this from happening? I assumed my background UIView would block any inputs.
Also, after the popover is dismissed, the screen is still dim. I tried the following but neither of them load after dismissing the popover so the View never gets set back to disable:
override func viewDidAppear(_ animated: Bool) {
dimView.isHidden = true
}
override func viewWillAppear(_ animated: Bool) {
dimView.isHidden = true
}
EDIT:
This is the code that I use to present the popover:
let popover = storyboard?.instantiateViewController(withIdentifier: "PopoverVC")
popover?.modalPresentationStyle = .popover
popover?.popoverPresentationController?.delegate = self as? UIPopoverPresentationControllerDelegate
popover?.popoverPresentationController?.sourceView = self.view
popover?.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popover?.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
dimView.isHidden = false
self.present(popover!, animated: false)
I realize that, dimView is not in PopoverVC, add it into PopoverVC and handle dismiss when tap on it.After the popover is dismissed viewDidAppear and viewWillAppear will not be called. So your screen is still blurry.If you add dimView into Popover, hope you can solve these issuses
I think you could solve your two problems with the UIPopoverPresentationControllerDelegate and a protocol/ delegate to tell the presenting viewcontroller when your are dismissing and hide your dimView.
The first issue can be implemented like this:
extension YourViewController: UIPopoverPresentationControllerDelegate {
func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
return false
}
For the second issue you can pass a function through delegation. Hopefully this link will help with that.
https://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/
Cheers

UIBarButtonItem not triggering IBAction

I'm trying to create a UIBarButtonItem that opens the camera once the button has been tapped. For some reason, my takePicture(_sender:) function doesn't seem to be getting called.
I originally tried to create my UIBarButtonItem using the Interface Builder. Here was the interface and a screenshot of the actions connected to the UIBarButtonItem:
And here is the code for my takePicture(_sender:) function:
#IBAction func takePicture(_ sender: UIBarButtonItem) {
print("Taking picture...")
let imagePicker = UIImagePickerController()
// If the device has a camera, take a picture; otherwise,
// just pick from photo library
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePicker.sourceType = .camera
} else {
imagePicker.sourceType = .photoLibrary
}
imagePicker.delegate = self
// Place image picker on the screen
present(imagePicker, animated: true, completion: nil)
}
The little circle next to my function declaration is filled in and connected properly:
However, when I load the simulator and press the button, the UIImagePickerController never appears and my print() function is never called in the code.
So, I then tried to declare the UIBarButtonItem programmatically to see if perhaps it was an issue under-the-hood of Xcode's Interface Builder. Here was my code:
(Note: I deleted the UIBarButtonItem from the Interface Builder and then I connected the UIToolbar to my code using an #IBOutlet.)
override func viewDidLoad() {
super.viewDidLoad()
let takePictureBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.camera, target: self, action: #selector(DetailViewController.takePicture))
toolBar.setItems([takePictureBarButton], animated: false)
}
#objc func takePicture() {
print("Taking picture...")
let imagePicker = UIImagePickerController()
// If the device has a camera, take a picture; otherwise,
// just pick from photo library
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePicker.sourceType = .camera
} else {
imagePicker.sourceType = .photoLibrary
}
imagePicker.delegate = self
// Place image picker on the screen
present(imagePicker, animated: true, completion: nil)
}
As a last ditch attempt at debugging this program and trying to find where the problem lies, I created a temporary button in my UI and connected that to my takePicture(_sender:) function instead (I changed the signature from a UIBarButtonItem to a UIButton). That worked perfectly. This tells me that the problem is not with the function itself, but has something to do with the connection.
I was seconds away from posting this question when I found a similar question. The user stated that the root of their problem lied in a UITapGestureRecognizer on their View Controller.
To solve my problem, I simply set my UITapGestureRecognizer's target to be my StackView instead of the the entire view.
Original:
Resolved:
I'd be curious to learn why the UITapGestureRecognizer stopped my UIBarButtonItem from being tapped, but not the normal UIButton. Seems a little strange...
Swift 4
I went through this problem and referenced above answers. The project I worked on had UIButton as navigation bar item and hence it comes under navigation item and I found out that the outlet for the IBAction should be connected to the button in the bar button item rather than connecting it to the bar button item itself. In mattkx4's question, the IBAction has 'UIBarButtonItem' as its sender. I fixed the issue by connecting the button inside the bar button item to the action.
As you can see there is a button inside the bar button item. Connect the action to this button and the action will be triggered.
make sure you connect your camera button with action for touchUpInside event

Adding Hamburger Button to SWRevealViewController in Swift

In the app I'm making I have a side menu that I used SWRevealViewController template to make. I made my own animated button to be the hamburger menu button so when its pressed the side menu will open. The problem is I can't figure out how to connect my animated button to the SWRevealViewController.
Here's the button code I made.
Animated Button
self.button = HamburgerButton(frame: CGRectMake(0, 0, 30, 30))
self.button.addTarget(self, action: #selector(home.toggle(_:)), forControlEvents:.TouchUpInside)
let refreshButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Refresh,
target: self, action: #selector(home.buttonMethod))
navigationItem.leftBarButtonItem = button
and heres the button that was used for the SWRevealViewController
override func viewDidLoad() {
super.viewDidLoad()
if revealViewController() != nil {
menuButton.target = revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}
Ive done a lot of research but just can't find out how to do it. I need the button I made, which is the first code, to be the one to access the SWRevealViewController and to open and close the side menu rather then the button, which is the second code, that came with the SWRevealViewController template. Any help will be Awesome!!
This is how I do it. You can adapt this to your needs.
let singleTap = UITapGestureRecognizer(target: self, action: #selector(tapDetected))
singleTap.numberOfTapsRequired = 1
sideMenuButton.userInteractionEnabled = true
sideMenuButton.addGestureRecognizer(singleTap)
func tapDetected() {
self.revealViewController().revealToggle(self)
}