I've created an actionSheet with 3 options that push to other view controllers and call a number. This option is on a button on a navigation bar on each screen of my app. I'm trying to find a way to reuse the code without literally re-typing it for every screen. I understand there is a way to do this through subclassing a UIButton but I've searched for days and can't find a definitive answer on how to actually code the subclass. My code right now is the following:
class moreButton: UIButton {
#IBAction func displayActionSheet(_ sender: Any) {
let alertController = UIAlertController(title: nil, message: "Get Your Roast On", preferredStyle: .actionSheet)
let followAction = UIAlertAction(title: "Follow Us", style: .default, handler: {(action: UIAlertAction!)->Void in self.performSegue(withIdentifier: "moveSegue", sender: self)
})
let shopAction = UIAlertAction(title: "Visit Shop", style: .default, handler: {(action: UIAlertAction!)->Void in self.performSegue(withIdentifier: "shopSegue", sender: self)
})
let callAction = UIAlertAction(title: "Call Us Now", style: .default) { _ in
let url:URL = URL(string: "tel://number")!
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(followAction)
alertController.addAction(shopAction)
alertController.addAction(callAction)
alertController.addAction(cancel)
self.present(alertController, animated: true, completion: nil)
}
}
I'm getting the error:
value of type 'moreButton' has no member 'performSegue'
in both the followAction and shopAction lines and "value of type 'moreButton' has no member 'present'" on the last line. This code was working when I had created an IBAction directly from the button but now it seems to have errors that I'm not sure how to correct.
You're getting those errors because performSegue and present are UIViewController methods.
Instead of subclassing UIButton, I'd create a new helper class, with a class method to build the UIAlertController for you. The method would accept a UIViewController as its parameter, so that it can build the UIAlertActions correctly.
You'd call this new method from displayActionSheet like:
let alertController = ActionSheetBuilder.build(viewController: self)
present(alert, animated: true, completion: nil)
Adapting your creation code into the new class would come out something like:
final class ActionSheetBuilder {
class func build(viewController: UIViewController) -> UIAlertController {
let alertController = UIAlertController(title: nil, message: "Get Your Roast On", preferredStyle: .actionSheet)
let followAction = UIAlertAction(title: "Follow Us", style: .default, handler: {(action: UIAlertAction!)->Void in viewController.performSegue(withIdentifier: "moveSegue", sender: viewController) })
let shopAction = UIAlertAction(title: "Visit Shop", style: .default, handler: {(action: UIAlertAction!)->Void in viewController.performSegue(withIdentifier: "shopSegue", sender: viewController) })
let callAction = UIAlertAction(title: "Call Us Now", style: .default) { _ in
let url:URL = URL(string: "tel://2845471035")!
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(followAction)
alertController.addAction(shopAction)
alertController.addAction(callAction)
alertController.addAction(cancel)
return alertController
}
}
Related
I have 4 tabs in the tab bar. Currently, I am working in the 4th tab, and having an imagePickerController. After the imagePickerController dismissed, it goes to the default tab (1st tab). How can I make it go to the current (4th) tab?
class EditMyPostViewController: UIViewController {
#IBOutlet weak var postImageView: UIImageView!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
#IBAction func updatePhotoTapped(_ sender: Any) {
let alert = UIAlertController(title: "Add a picture", message: "How do you want to upload the picture?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { action in
self.takePhotoWithCamera()
}))
alert.addAction(UIAlertAction(title: "Use Existing Photo", style: .default, handler: { action in
self.getPhotoFromLibrary()
}))
self.present(alert, animated: true)
}
}
extension EditMyPostViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func takePhotoWithCamera() {
if (!UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera)) {
let alertController = UIAlertController(title: "No Camera", message: "The device has no camera.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
present(alertController, animated: true, completion: nil)
} else {
imagePicker.allowsEditing = false
imagePicker.sourceType = .camera
present(imagePicker, animated: true, completion: nil)
}
}
func getPhotoFromLibrary() {
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
{
postImageView.image = image
}
dismiss(animated: true, completion: nil)
}
}
The imagePicker is present in the 2 functions takePhotoWithCamera() and getPhotoFromLibrary().
In the last function, I tried to dismiss(animated: true, completion: nil), but it goes to the default tab instead of the current tab. How can I present the current ViewController?
I tried
present(self, animated: true, completion: nil)
But it will cause an Exception: Application tried to present modally an active controller
I'm trying to change the color of the accept button. This is my code.
let alert = UIAlertController(title: "Aviso",
message: "¿Desea eliminar el registro?",
preferredStyle: .alert)
//custome dialog
// Restyle the buttons of the Alert
alert.view.tintColor = UIColor.black
alert.view.backgroundColor = UIColor.yellow
// Accept button
let submitAction = UIAlertAction(title: "Aceptar", style: .default, handler: { (action) -> Void in
self.removePro()
})
// Cancel button
let cancel = UIAlertAction(title: "Cancelar", style: .destructive, handler: { (action) -> Void in })
// Add action buttons and present the Alert
alert.addAction(cancel)
alert.addAction(submitAction)
present(alert, animated: true, completion: nil)
Try this
submitAction.setValue(UIColor.blue, forKey: "titleTextColor")
I have an UIImagePickerController that works, but I wanted to let the user decide whether he shoots the image or picks it from library. So this is my code trying to do it with alert:
#IBAction func cameraButton(_ sender: UIButton) {
picker.allowsEditing = true
let alert = UIAlertController(title: "Choose one of the following:", message: "", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { action in
self.picker.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { action in
self.picker.sourceType = .camera
}))
self.present(alert, animated: true, completion: nil)
present(picker, animated: true, completion: nil)
}
However, once I click on one of the actions in the alert, nothing happens, it just gets out of the alert but not presenting my picker
Any help is appreciated
I solved it by presenting inside the action like this:
#IBAction func cameraButton(_ sender: UIButton) {
picker.allowsEditing = true
let alert = UIAlertController(title: "Choose one of the following:", message: "", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { action in
self.picker.sourceType = .photoLibrary
self.present(self.picker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { action in
self.picker.sourceType = .camera
self.present(self.picker, animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
I want the user to be taken to a new viewController after clicking "use photo" after taking a picture. However, the segue is never performed. I have attempted this segue by connecting two viewControllers via a manual segue. I have a print statement in my imagePickerController function which is where my segue code is. This print statement prints when I click "use photo", so why is my segue be ignored? I tried this exact same segue code within a "#IBAction func someButton (_sender: UIButton)" and it worked fine? Any help would be appreciated.
Here is my code:
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
#IBOutlet weak var imageTake: UIImageView!
var imagePicker: UIImagePickerController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func takePhoto(_ sender: UIButton) {
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
present(imagePicker, animated: true, completion: nil)
}
#IBAction func photoLib(_ sender: UIButton) {
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
#IBAction func save(_ sender: AnyObject) {
UIImageWriteToSavedPhotosAlbum(imageTake.image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
imagePicker.dismiss(animated: true, completion: nil)
imageTake.image = info[UIImagePickerControllerOriginalImage] as? UIImage
print("made it")
performSegue(withIdentifier: "new", sender: self)
}
}
Here's a suggestion. You have this:
imagePicker.dismiss(animated: true, completion: nil)
// ...
performSegue(withIdentifier: "new", sender: self)
Change it to this:
imagePicker.dismiss(animated: true, completion: {
performSegue(withIdentifier: "new", sender: self)
})
That way, we don't try to perform the segue until the image picker is in fact completely dismissed.
If that doesn't work, then I would have to conclude that there is no such segue as "new" coming from this view controller. But you have not shown your storyboard so I can't be certain.
Code:
let alertController = UIAlertController(title: "StopRequest", message: msg, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction!) in
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
I create a UIAlertViewController in swift3.
Alertview is working fine.Please help me on how to handle ok and cancel events.If we have more than one alert how to differentiate them?.thanks in advance
let alert = UIAlertController(title: "Wrong Email Or Password", message: "Please Check Your Email or Password", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default)
{
_ in // add actions here
}
)
self.present(alert, animated: true, completion: nil)