I'm still learning Swift and therefor don't understand how certain things work - like Placeholders. I installed HGPlaceholders into my project for use with TableViews that I have downloading information from Firebase. I can't seem to figure out how to give the various screens' (there's multiple screens and they each have one "Try Again!" or "Cancel" button) button an action though.
Would someone who is familiar with HGPlaceholders please help me out? How do I give something like
tableView.showLoadingPlaceholder()
an action? Currently it just prints something out to the console, by default.
Yes, I read the documentation for it. Yes, I searched the internet for help. No, I couldn't find anything addressing this question.
Thanks!
HGPlaceholders: HGPlaceholders Documentation
This is what the function that by default prints something when the button in the placeholder is tapped looks like:
#IBAction func sendPlaceholderAction(_ sender: Any) {
onActionButtonTap?()
print("Placeholder action button tapped")
}
I figured it out... took me forever cause I'm stupid.
The actions are handled in this function that you place at the bottom of the class your table view is located in:
extension TestViewController: PlaceholderDelegate {
func view(_ view: Any, actionButtonTappedFor placeholder: Placeholder) {
print(placeholder.key.value)
if placeholder.key.value == "loading" {
print("The placeholder is the Loading screen and Cancel button")
} else if placeholder.key.value == "noResults" {
print("The placeholder is the noResults screen and Try Again button")
} else if placeholder.key.value == "noConnection" {
print("The placeholder is the noConnection screen and Try Again button")
} else if placeholder.key.value == "error" {
print("The placeholder is the error screen and Try Again button")
}
}
}
This is an example of giving an action to each of the four .default options.
Hope this helps anyone else who couldn't figure it out haha!
Side note: One other thing, you have to set your tableView's placeholderDelegate in the viewDidLoad as well.
tableView.placeholderDelegate = self
If you don't, the function will never execute.
Related
I'm working on an app that displays a today extension with some information. When I tap on the today extension, it opens the app and navigates to a subview from the root to display the information. Normally the user would then click the back arrow to go back to the main view, but there is no way to tell if this is actually done. It is possible for the user to go back to the today extension and tap again. When this is done, the subview is opened once again with new information. If this is done a bunch of times, I end up with a bunch of instances of the subview and I have to click the back button on each of them to get back to the main view.
My question: Is it possible to check if the subview is already visible? I'd like to be able to just send updated information to it, instead of having to display an entirely new view.
I am currently handling this by keeping the instance of the UIViewController at the top of my root. If it is not nil, then I just pass the information to it and redraw. If it is nil, then I call performSegue and create a new one.
I just think that there must be a better way of handling this.
Edit: Thanks to the commenter below, I came up with this code that seems to do what I need.
if let quoteView = self.navigationController?.topViewController as? ShowQuoteVC {
quoteView.updateQuoteInformation(usingQuote: QuoteService.instance.getQuote(byQuoteNumber: quote))
}
else {
performSegue(withIdentifier: "showQuote", sender: quote)
}
This is different from the suggested post where the answer is:
if (self.navigationController.topViewController == self) {
//the view is currently displayed
}
In this case, it didn't work because I when I come in to the app from the Today Extension, it goes to the root view controller. I needed to check whether a subview is being displayed, and self.navigationController.topViewcontroller == self will never work because I am not checking to see if the top view controller is the root view controller. The suggestions in this post are more applicable to what I am trying to accomplish.
u can use this extension to check for currently displayed through the UIApplication UIViewController:
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
and usage example:
if let topController = UIApplication.topViewController() {
if !topController.isKind(of: MainViewController.self) { //MainViewController- the controller u wish to equal its type
// do action...
}
}
I have a problem with the above stated. I can not find the exact information on the forums. Most of them are outdated and I have written the code programmatically. I have a controller that contains a view to edit the profile. I can not access that after changing the function listed below. I have a rootviewcontroller set to something else, but I tried the UiApplication calls anyway and it return nil and I can not open the profile controller. This is the function listed below.
#objc func handleOpen2() {
(UIApplication.shared.keyWindow?.rootViewController as? BaseSlidingController)?.openMenu()
}
Xcode does not give me an error but I can not get my menu to open. My rootviewcontroller is set to something else in app delegate. I have a controller that is used to control the sliding menu when I press the edit profile button.
func openMenu() {
isMenuOpened = true
redViewLeadingConstraint.constant = menuWidth
redViewTrailingConstraint.constant = menuWidth
performAnimations()
setNeedsStatusBarAppearanceUpdate()
}
This code is used to open my side bar menu with the information I need and also to perform animations as well. I was wondering if someone had any idea what I can do different instead in my handleOpen2 function. If you need more code, please let me know. Thanks
On swift 5 version:
(UIApplication.shared.windows.first?.rootViewController as? BaseSlidingController)?.openMenu()
I have a NSPopUpButton with a built up NSMenu.
However, when an NSMenuItem is selected, it keeps going back to the first item.
In this example, I'd expect "Maged" to be selected.
Any ideas?
Related question/answer: https://stackoverflow.com/a/53387962/157656
Duplicate:
It's been suggested that this is a duplicate of the question
How do I change/modify the displayed title of an NSPopUpButton
"I would like an NSPopUpButton to display a different title than the title of the menu item that is selected."
However, my question was about getting the NSPopUpButton to show the selected item.
In the end, I changed how I did it.
I am using a NSButton to show the menu and NSTextField to display the results.
If anyone is interested in the details, here they are.
Build the menu up and use .representedObject to store whatever you need to access at the other end. I used a struct with the name and code the in it.
You need to assign the NSMenu to the NSButton.menu
Then have a click, something like this.
#IBAction func changeVoiceClicked(_ sender: NSButton)
{
if let event = NSApplication.shared.currentEvent {
NSMenu.popUpContextMenu(sender.menu!, with: event, for: sender)
}
}
Your NSMenuItem should have an action on it, which using a selector points to a function.
Something like this:
#objc func voiceChanged(sender: NSMenuItem)
{
// cope will nil
var voice : VoiceDetail = VoiceDetail();
if (sender.representedObject != nil) {
voice = sender.representedObject as! VoiceDetail;
}
// Do what you need to on menu select.
// update text field.
}
I searched everywhere and can't seem to find anything on this. For example I want to have more then one UITextField on the same screen. If I tap on one and type in information and click return it does an action. If you tap in the second one and return the keyboard it does a different action.
Any suggestions or help would be awesome thanks!
One option is to use tags. In the example below you can select the next textfield, and only on the last one do we login. You could use cases to do whatever you'd like
//automatically move to the next field
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
let next = textField.tag + 1
// Find next responder
if let nextField = view.viewWithTag(next) as? UITextField {
nextField.becomeFirstResponder()
} else {
// Not found, so remove keyboard.
textField.resignFirstResponder()
//do the final action to login
loginAction()
}
return false
}
Since iOS 9, you can connect the “Primary Action Triggered” event of your UITextField to an action method. So you can connect each text field's “Primary Action Triggered” event to a separate action method to give the text fields different actions.
See this answer for a demo: https://stackoverflow.com/a/26288292/77567
I realized I was really over thinking it.. Took another look and saw what I was trying to do was a lot easier then I thought.. Thanks everybody who helped! (just an example below)
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if field1.resignFirstResponder() {
print("yellow")
}
if field2.resignFirstResponder() {
print("blue")
}
return (true)
}
I have a set of 12 UIImageViews in my storyboard, and, for argument's sake, I want to get each one to print to logs "You just tapped image x", when the user taps on it, where x is the number of image tapped, from 1-12). So i need to detect which image is tapped, and do something depending on that information. What would be the best way to do this, in Swift 3 ?
(I assume 12 IBActions -treat them as button with an image on background- is really bad code. Also they need to be placed on specific positions on top of a background image, so cannot use UICollectionView to do this.) Thanks
First of all, I think using a collectionView is a better approach to achieve what do you want. However, you'll need to:
Set userInteractionEnabled to true for all of your imageViews.
Set -sequential- tag for all of your imageViews, for example image1.tag = 1, image2.tag = 2 ... and so on.
Implement a method to be the target of all of your images tapping, it should be similar to this:
func imageViewTapped(imageView: UIImageView) {
print("You just tapped image (imageView.tag)")
}
Create -one single- tap gesture and assign the implemented method to its selector:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(imageViewTapped))
Finally, add the tapGesture for all of your image, for example: image1.addGestureRecognizer(tapGesture), image2.addGestureRecognizer(tapGesture)... and so on.
Hope this helps.
It's not bad code per-se, but if you did it that way, or with tap gestures on each of the ImageViews you would likely want to separate out that part of the logic.
There are other approaches/views you could use to manage this kind of thing better, especially if this is supposed to scale, but with your constraints this is what I would suggest:
Either add TapGestureRecognizers to your imageViews or make them buttons, then connect all their actions to this:
#IBAction func phoneWasPressed(sender: AnyObject) {
guard let tappedImageView = sender as? UIImageView else {
return
}
switch tappedImageView {
case imageView1:
//do something
case imageView2:
// do something else
//etc.
default:
break
}
switch sender
}
I don't think it's a bad idea at all to have 12 buttons. Assign each of them a tag from 1-12 and connect them to the same IBAction.
#IBAction func didTapImageButton(button: UIButton) {
print("You just tapped image \(button.tag)")
}