This is a slightly odd one which I'm not sure where to start debugging. I have a UILabel on a standard view which I update the text based on certain conditions. From the IB I have set default text that reads 'Loading...' and then the viewDidAppear method updates the text based on the conditions. This works fine, however, if I then rotate my iPhone (or simulator) it reverts the UILabel back to the standard text of 'Loading...'.
What's interesting is that when I view it on an iPad, both simulator and actual device it doesn't change the text back to the default and acts as I would expect.
I have tried detecting an orientation change and resetting the text but that has no effect, it's a bit like the label has become locked to default state.
Happy to provide code if necessary but I'm really not sure what code is relevant as it's a straight forward label and updating it's text.
Thanks
import UIKit
class PredictionViewController: UIViewController {
var predictionData: Predictions!
var embeddedVC: PredictionsTableViewController?
#IBOutlet weak var messageTextBox: UILabel!
#IBOutlet weak var predictionSubmitButton: UIButton!
#IBOutlet weak var predictionSubmitButtonHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//self.messageTextBox.isEditable = false
NotificationCenter.default.addObserver(self, selector: #selector(settingChanged(notification:)), name: UserDefaults.didChangeNotification, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
let preferences = UserDefaults.standard
if (preferences.object(forKey: "regID") == nil)
{
loadLoginScreen()
}
else {
let sv = UIViewController.displaySpinner(onView: self.view)
let predictionStatus = preferences.object(forKey: "predictionStatus") as! String
switch (predictionStatus) {
case "inplay":
setInplay(view: self)
case "finished":
setFinished(view: self)
case "predict":
setPredict(view: self)
default:
self.messageTextBox.text = "Error!"
}
if (self.messageTextBox.isHidden) {
self.messageTextBox.isHidden = false
}
UIViewController.removeSpinner(spinner: sv)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "predictionSegue") {
if let vc = segue.destination as? PredictionsTableViewController {
// get a reference to the embedded VC
self.embeddedVC = vc
}
}
}
#objc func settingChanged(notification: NSNotification) {
let preferences = UserDefaults.standard
let predictionStatus = preferences.object(forKey: "predictionStatus") as! String
switch (predictionStatus) {
case "inplay":
setInplay(view: self)
case "finished":
setFinished(view: self)
case "predict":
setPredict(view: self)
default:
messageTextBox.text = "Error!"
}
}
func setInplay(view: PredictionViewController) {
view.messageTextBox.text = "In Play!"
view.predictionSubmitButtonHeight.constant = 0
}
func setFinished(view: PredictionViewController) {
view.messageTextBox.text = "Finished!"
view.predictionSubmitButtonHeight.constant = 0
}
func setPredict(view: PredictionViewController) {
view.messageTextBox.text = "Predict Now!"
view.predictionSubmitButton.isEnabled = true
view.predictionSubmitButton.setTitle("Submit", for: .normal)
view.predictionSubmitButtonHeight.constant = 58
}
#IBAction func predictionSubmitButtonAction(_ sender: UIButton) {
let preferences = UserDefaults.standard
let sv = UIViewController.displaySpinner(onView: self.view)
CheckTime(finished: { isSuccess in
switch (isSuccess) {
case "inplay":
preferences.set("inplay", forKey: "predictionStatus")
//too late alert
case "finished":
preferences.set("finished", forKey: "predictionStatus")
//too late alert
case "predict":
preferences.set("predict", forKey: "predictionStatus")
if let predictionData = self.embeddedVC?.getPredictionData() {
//send back to website
let regID = preferences.object(forKey: "regID")
let url = URL(string: "[URL]")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let bodyData = "{}"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let data = data, let _ = response, error == nil else
{
DispatchQueue.main.async(
execute: {
UIViewController.removeSpinner(spinner: sv)
self.displayAlertMessage(message: "response error: \(String(describing: error?.localizedDescription))", type: "error")
}
)
return
}
do {
let decoder = JSONDecoder()
let predictionResult = try decoder.decode(ReturnData.self, from: data)
DispatchQueue.main.async(
execute: {
if (predictionResult.success) {
self.displayAlertMessage(message: predictionResult.message, type: "message", title: "Predictions Received")
}
else {
self.displayAlertMessage(message: "response error: \(String(describing: error?.localizedDescription))", type: "error")
}
UIViewController.removeSpinner(spinner: sv)
}
)
} catch {
DispatchQueue.main.async(
execute: {
UIViewController.removeSpinner(spinner: sv)
self.displayAlertMessage(message: "response error: \(error)", type: "error")
}
)
return
}
})
task.resume()
}
default:
UIViewController.removeSpinner(spinner: sv)
self.messageTextBox.text = "Error!"
preferences.set("error", forKey: "predictionStatus")
}
preferences.synchronize()
if (self.messageTextBox.isHidden) {
self.messageTextBox.isHidden = false
}
})
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("Landscape")
//imageView.image = UIImage(named: const2)
} else {
print("Portrait")
//imageView.image = UIImage(named: const)
}
self.messageTextBox.text = "Error!"
}
Can You use this Delegate method for screen orientation.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
}, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
//refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here
**//---> Set the text for label here.**
})
super.viewWillTransition(to: size, with: coordinator)
}
I believe that you should take your code off viewDidAppear and put inside viewDidLoad.
If you don't want to use the code in other orientation, you should uncheck for all other orientations and only choose the one you want to be implemented, that will fix your problem, however if you want to works in other orientations, try to do what I said and see if it works.
Even none of what I just said works, try to look around your code if you have a condition to changes the text when transition happens.
One more thing, just a tip, avoid putting too much code inside of a simple action, try to refactoring in other Methods and then call it inside your action.
Related
How can I customize the Firebase UI Auth Picker controller with custom buttons, custom actions, background, loader etc..
I already try to subclass the FUIAuthPickerViewController but we can't access to login buttons
This is how you can create your own class of FUIAuthPickerViewController:
Create FUICustomLoginController.swift with:
import UIKit
import FirebaseUI
import FirebaseAuth
class FUICustomLoginController: ViewController {
var authUI: FUIAuth! = FUIAuth.defaultAuthUI()
var auth: Auth = Auth.auth()
private func didSignIn(auth: AuthCredential?, error: Error?, callBack: AuthResultCallback?) {
let callBack: (AuthDataResult?, Error?) -> Void = { [unowned self] result, error in
callBack?(result?.user, error)
self.authUI.delegate?.authUI?(self.authUI, didSignInWith: result, error: error)
}
if let auth = auth {
self.auth.signInAndRetrieveData(with: auth, completion: callBack)
} else if let error = error {
callBack(nil, error)
}
}
func signIn<T: FUIAuthProvider>(type: T.Type, defaultValue: String? = nil) {
try? self.authUI.signOut() // logout from google etc..
self.authUI.providers.first(where: { $0 is T })?.signIn(withDefaultValue: defaultValue, presenting: self, completion: self.didSignIn)
}
}
Subclass your controller from FUICustomLoginController:
class LoginPickerController: FUICustomLoginController {
override func viewDidLoad() {
super.viewDidLoad()
// Customize authUI if needed
//self.authUI.providers = ...
self.authUI.delegate = self
}
#IBAction func loginFacebook(_ sender: Any) {
self.signIn(type: FUIFacebookAuth.self)
}
#IBAction func loginGoogle(_ sender: Any) {
self.signIn(type: FUIGoogleAuth.self)
}
#IBAction func loginPhone(_ sender: Any) {
self.signIn(type: FUIPhoneAuth.self)
}
}
extension LoginPickerController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
// perform login actions
}
}
You can customize the default buttons, add images etc.. (a working hack )
class SignInViewController: FUIAuthPickerViewController {
weak var delegate: signInProtocol?
// Unhashed nonce.
fileprivate var currentNonce: String?
var backgView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
for each in view.subviews[0].subviews[0].subviews[0].subviews {
if let button = each as? UIButton {
button.layer.cornerRadius = 20.0
button.layer.masksToBounds = true
///do any other button customization here
}
}
///add background image
let scrollView = view.subviews[0]
scrollView.backgroundColor = .clear
let contentView = scrollView.subviews[0]
contentView.backgroundColor = .clear
let background = UIImage(named: "imagename")
let backgroundImageView = UIImageView(image: background)
backgroundImageView.contentMode = .scaleToFill
view.insertSubview(backgroundImageView, at: 0)
}
}
Currently I bought a source code for a social media app that uses firebase for the sign up/ log in page, but I'm seeing that log in page has no background image and sign up buttons are at the bottom leaving a blank screen on the entire page.
I'm a noobi when it comes to coding in xCode so hope you can help me with adding a background image.
So currently I have 2 files that control the Auth screen (Authclient.swift & WelcomeViewController.swift)
I've been going through the files and looks like "WelcomeViewController.swift" controls the sign in screen... This is the code I have in that file:
import UIKit
import SwiftHEXColors
import Firebase
import FirebaseAuth
import FirebaseAuthUI
import FirebaseGoogleAuthUI
import FirebaseFacebookAuthUI
import FirebaseTwitterAuthUI
import FirebasePhoneAuthUI
class WelcomeViewController: UIViewController, FUIAuthDelegate {
#IBOutlet weak var progressView:UIView? // view shown while data is loading
#IBOutlet weak var welcomeView:UIView? // view when data is loaded. like sign-in or intro
var client:AuthClient?
override func viewDidLoad() {
self.welcomeView?.isHidden = true
self.progressView?.isHidden = false
let config = RemoteConfig.remoteConfig()
#if DEBUG
config.configSettings = RemoteConfigSettings(developerModeEnabled: true)
#endif
config.fetch(withExpirationDuration: 100) { (status, error) -> Void in
if status == .success {
print("Config fetched!")
config.activateFetched()
} else {
print("Config not fetched")
print("Error: \(error?.localizedDescription ?? "No error available.")")
}
self.defineTheme(config)
self.welcomeView?.isHidden = false
self.progressView?.isHidden = true
// if user authorized, go to main page
if (Auth.auth().currentUser) != nil {
self.performSegue(withIdentifier: "auth.mute", sender: nil)
} else {
self.buttonPressed(self)
}
}
}
// FIRAuthUIDelegate
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
if let errorHandler = error as NSError? {
self.showError(errorHandler.localizedDescription)
// print user-info. find more here: https://firebase.google.com/docs/auth/ios/errors
print(errorHandler.userInfo)
} else {
if let currentUser = user {
// update displayname and photo
let name = currentUser.displayName ?? kDefaultUsername
let photo = currentUser.photoURL?.absoluteString ?? kDefaultProfilePhoto
client?.saveUser(userId: currentUser.uid,
name: name,
photo: photo,
override: false)
//user?.sendEmailVerification(completion: nil)
}
self.performSegue(withIdentifier: "auth", sender: nil)
}
}
// Helpers
func showError(_ error:String) {
print("Error: \(error)")
let alert = UIAlertController(title: kAlertErrorTitle, message: error, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: kAlertErrorDefaultButton, style: .default) { (action) in })
self.present(alert, animated: true) {}
}
func defineTheme(_ config:RemoteConfig) {
var primary = UIColor.white
var secondary = UIColor.blue
if let string = config[kPrimaryColor].stringValue, !string.isEmpty {
primary = UIColor(hexString: string)!
}
if let string = config[kSecondaryColor].stringValue, !string.isEmpty {
secondary = UIColor(hexString: string)!
}
UINavigationBar.appearance().barTintColor = primary
UINavigationBar.appearance().tintColor = secondary
UIBarButtonItem.appearance().setTitleTextAttributes(
[NSAttributedStringKey.foregroundColor:secondary], for: UIControlState.normal)
UITabBar.appearance().barTintColor = primary
UITabBar.appearance().tintColor = secondary
UIButton.appearance().tintColor = secondary
}
// Actions
#IBAction func buttonPressed(_ sender: AnyObject) {
let authUI = FUIAuth.defaultAuthUI()
authUI?.delegate = self
/*
* Uncommend this lines to add Google and Facebook authorization. But first
* enabled it in Firebase Console. More information you can find here:
* https://firebase.google.com/docs/auth/ios/google-signin
* https://firebase.google.com/docs/auth/ios/facebook-login
*/
let providers: [FUIAuthProvider] = [
// FUIGoogleAuth(),
// FUIFacebookAuth(),
// FUITwitterAuth(),
FUIPhoneAuth(authUI:authUI!),
]
authUI?.providers = providers
/*
kEulaUrl needs to be set in Config.swift file. required for publishing
*/
authUI?.tosurl = URL(string:kEulaUrl)
if (Auth.auth().currentUser) != nil {
self.performSegue(withIdentifier: "auth.mute", sender: nil)
} else {
let authViewController = authUI!.authViewController()
self.present(authViewController, animated: true) {
// ..
}
}
}
}
Can anyone point me in the right direction to add a background image to this screen. Already have my 3 images in Assets.xcassets named bgLogin.imageset.
Thanks
This is what you want to do.
Create an extension of their baseViewController
extension FUIAuthBaseViewController {
Inside of that extension, override their viewWillAppear() and set the image there
open override func viewWillAppear(_ animated: Bool) {
self.navigationItem.leftBarButtonItem = nil
self.view.backgroundColor = .white
// if view is base view add logo as subview
let vc = self.navigationController?.viewControllers.first
if vc == self.navigationController?.visibleViewController {
makeLogoImage()
} else {
// hide the image in proceeding views by covering it with a white background
vc?.view.backgroundColor = .white
}
}
/**
Create imageView and display it at the top of the screen.
*/
func makeLogoImage() {
let imageView = UIImageView(image: UIImage(named: "angel.png"))
let width = view.frame.width
let height = view.frame.height
imageView.frame = CGRect(x: width / 4, y: height / 8 , width: width / 2, height: width / 2)
imageView.contentMode = .scaleAspectFill
self.view.addSubview(imageView)
self.view.sendSubview(toBack: imageView)
}
I am making a view controller to make a camera view controller like snapchat camera. my code below is worked perfectly for iOS 11 or above. to be honest, I don't really grasp my code since i just follow along the tutorial for this snapchat like camera view controller
import UIKit
import AVFoundation
import SVProgressHUD
class CameraVC: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var cameraButton: DesignableButton!
#IBOutlet weak var retryButton: DesignableButton!
// to receive data from MainMenuVC
var employeeData : Employee?
var checkinData = CheckIn()
var captureSession = AVCaptureSession()
// which camera input do we want to use
var backCamera: AVCaptureDevice?
var frontCamera: AVCaptureDevice?
// to keep track which camera do we use currently
var currentDevice: AVCaptureDevice?
var photoOutput: AVCapturePhotoOutput?
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
var toggleCameraGestureRecognizer = UISwipeGestureRecognizer()
var zoomInGestureRecognizer = UISwipeGestureRecognizer()
var zoomOutGestureRecognizer = UISwipeGestureRecognizer()
var thereIsAnError : Bool = false {
didSet {
if thereIsAnError {
cameraButton.isHidden = true
cameraButton.isEnabled = false
retryButton.isHidden = false
retryButton.isEnabled = true
} else {
cameraButton.isHidden = false
cameraButton.isEnabled = true
retryButton.isHidden = true
retryButton.isEnabled = false
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
getDateTimeFromServer()
// initial value
thereIsAnError = false
timeLabel.text = ""
dateLabel.text = ""
cameraButton.isEnabled = false
cameraButton.alpha = 0.4
setupCaptureSession()
setupDevice()
setupInputOutput()
setupPreviewLayer()
startRunningCaptureSession()
setGestureRecognizer()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if checkinData.dateTime != nil {
SVProgressHUD.dismiss()
}
}
#IBAction func shutterButtonDidPressed(_ sender: Any) {
// when the button is pressed, we capture the image and set the photoOutput
let settings = AVCapturePhotoSettings()
photoOutput?.capturePhoto(with: settings, delegate: self)
// perform segue is below in the AVCapturePhotoCaptureDelegate
}
#IBAction func retryButtonDidPressed(_ sender: Any) {
if checkinData.dateTime == nil {
getDateTimeFromServer()
}
}
}
extension CameraVC {
// MARK: - Helper Methods
// MARK: - Helper Methods
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToCheckinDetail" {
let checkinDetailTVC = segue.destination as! CheckinDetailVC
checkinDetailTVC.dataOfCheckin = checkinData
checkinDetailTVC.dataOfEmployee = employeeData
// to set the navbar back button title in the checkinDetailVC
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
}
func getDateTimeFromServer() {
SVProgressHUD.show(withStatus: "Loading Data")
NetworkingService.getCurrentTimeFromServer { (result) in
switch result {
case .failure:
self.thereIsAnError = true
SVProgressHUD.dismiss()
self.showAlert(alertTitle: "Sorry", alertMessage: "Internet connection issue, please tap the retry button.", actionTitle: "Back")
case .success(let timeFromServer) :
guard let stringDateTimeServer = timeFromServer as? String else {return}
self.checkinData.dateTime = stringDateTimeServer
let dateTimeService = DateTimeService(fromDateTimeString: stringDateTimeServer)
let time = dateTimeService.parsingDateAndTime()?.timeOnly
self.timeLabel.text = "\(time ?? "-")"
self.dateLabel.text = DateTimeService.changeFormat(of: stringDateTimeServer, toFormat: "dd MMM yyyy")
self.cameraButton.isEnabled = true
self.cameraButton.alpha = 1
self.thereIsAnError = false
SVProgressHUD.dismiss()
}
}
}
func setGestureRecognizer() {
// change camera from front to back
toggleCameraGestureRecognizer.direction = .up
toggleCameraGestureRecognizer.addTarget(self, action: #selector(self.switchCamera))
view.addGestureRecognizer(toggleCameraGestureRecognizer)
// Zoom In recognizer
zoomInGestureRecognizer.direction = .right
zoomInGestureRecognizer.addTarget(self, action: #selector(zoomIn))
view.addGestureRecognizer(zoomInGestureRecognizer)
// Zoom Out recognizer
zoomOutGestureRecognizer.direction = .left
zoomOutGestureRecognizer.addTarget(self, action: #selector(zoomOut))
view.addGestureRecognizer(zoomOutGestureRecognizer)
}
func setupCaptureSession() {
// to specify image resolution and quality we want, we set to the highest resolution possible
captureSession.sessionPreset = AVCaptureSession.Preset.photo
}
func setupDevice() {
// to decide whether we use front or back camer
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if device.position == AVCaptureDevice.Position.back {
backCamera = device
} else if device.position == AVCaptureDevice.Position.front {
frontCamera = device
}
}
// default device
currentDevice = frontCamera
}
func setupInputOutput() {
// after the camera capture that image (input), we generate the image DATA (output)
// put the input and output to capture Session
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice!)
captureSession.addInput(captureDeviceInput)
photoOutput = AVCapturePhotoOutput()
photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
captureSession.addOutput(photoOutput!)
} catch {
print(error)
}
}
func setupPreviewLayer() {
// to display image data on the screen
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
cameraPreviewLayer?.frame = self.view.frame
self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}
#objc func switchCamera() {
captureSession.beginConfiguration()
// Change the device based on the current camera
let newDevice = (currentDevice?.position == AVCaptureDevice.Position.back) ? frontCamera : backCamera
// Remove all inputs from the session
for input in captureSession.inputs {
captureSession.removeInput(input as! AVCaptureDeviceInput)
}
// Change to the new input
let cameraInput:AVCaptureDeviceInput
do {
cameraInput = try AVCaptureDeviceInput(device: newDevice!)
} catch {
print(error)
return
}
if captureSession.canAddInput(cameraInput) {
captureSession.addInput(cameraInput)
}
currentDevice = newDevice
captureSession.commitConfiguration()
}
#objc func zoomIn() {
if let zoomFactor = currentDevice?.videoZoomFactor {
if zoomFactor < 5.0 {
let newZoomFactor = min(zoomFactor + 1.0, 5.0)
do {
try currentDevice?.lockForConfiguration()
currentDevice?.ramp(toVideoZoomFactor: newZoomFactor, withRate: 1.0)
currentDevice?.unlockForConfiguration()
} catch {
print(error)
}
}
}
}
#objc func zoomOut() {
if let zoomFactor = currentDevice?.videoZoomFactor {
if zoomFactor > 1.0 {
let newZoomFactor = max(zoomFactor - 1.0, 1.0)
do {
try currentDevice?.lockForConfiguration()
currentDevice?.ramp(toVideoZoomFactor: newZoomFactor, withRate: 1.0)
currentDevice?.unlockForConfiguration()
} catch {
print(error)
}
}
}
}
func startRunningCaptureSession() {
// to start capturing the data
captureSession.startRunning()
}
}
extension CameraVC: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation() {
checkinData.photo = UIImage(data: imageData)
performSegue(withIdentifier: "goToCheckinDetail", sender: nil)
}
}
}
but when I set my deployment target to iOS 10.3, I got an error that said some method is only available for iOS 11 or newer.
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation() {
checkinData.photo = UIImage(data: imageData)
performSegue(withIdentifier: "goToCheckinDetail", sender: nil)
}
}
AVCapturePhoto' is only available on iOS 11.0 or newer
fileDataRepresentation()' is only available on iOS 11.0 or newer
and
func setupInputOutput() {
// after the camera capture that image (input), we generate the image DATA (output)
// put the input and output to capture Session
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice!)
captureSession.addInput(captureDeviceInput)
photoOutput = AVCapturePhotoOutput()
photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
captureSession.addOutput(photoOutput!)
} catch {
print(error)
}
}
'jpeg' is only available on iOS 11.0 or newer
Please help me, I need some function that equal to those function for iOS 10 (at least) or below.
Create an AVCapturePhotoOutput object. Use its properties to determine supported capture settings and to enable certain features (for example, whether to capture Live Photos).
fileprivate var photoOutput: AVCapturePhotoOutput!
Create and configure an AVCapturePhotoSettings object to choose
features and settings for a specific capture (for example, whether to enable image stabilization or flash).
photoOutput = AVCapturePhotoOutput()
if self.session.canAddOutput(photoOutput) {
self.session.addOutput(photoOutput)
}
Capture an image by passing your photo settings object to the
capturePhoto(with:delegate:) method along with a delegate object implementing the AVCapturePhotoCaptureDelegate protocol. The photo capture output then calls your delegate to notify you of significant events during the capture process.
queue.async { self.photoOutput.capturePhoto(with: AVCapturePhotoSettings(), delegate: self) }
I am looking at adding an inital note to the note page within my app. this is so that when people click to the notes part there will be some detail on how to use it rather than just a big empty screen. I have no idea where to implement this though. Could you please help, below is the page where it talks about the dictionaries.
import UIKit
import MessageUI
class DetailViewController: UIViewController, MFMailComposeViewControllerDelegate, UITextViewDelegate {
#IBOutlet weak var tView: UITextView!
#IBAction func BarButton(sender: UIBarButtonItem) {
let textToShare = ""
if let myWebsite = NSURL(string: "")
{
let objectsToShare = [textToShare, myWebsite]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
self.presentViewController(activityVC, animated: true, completion: nil)
}
OpenMail()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tView.text = (allNotes[currentNoteIndex] as Note).note
tView.becomeFirstResponder()
// Set controller as swipe gesture recogniser, to allow keyboard dismissal for text box
var swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "dismissKeyboard")
swipe.direction = UISwipeGestureRecognizerDirection.Down
self.view.addGestureRecognizer(swipe)
self.tView.delegate = self
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if tView.text == "" {
allNotes.removeAtIndex(currentNoteIndex)
}
else {
(allNotes[currentNoteIndex] as Note).note = tView.text
}
Note.saveNotes()
noteTable?.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
// Open mail controller on screen and prepare with preset values.
let mailComposerVC = MFMailComposeViewController()
var MessageText: String!
MessageText = tView.text
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients([""])
mailComposerVC.setSubject("")
mailComposerVC.setMessageBody(MessageText, isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert() {
// Alert user to email error
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate Method
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
func OpenMail() {
//Function to open mail composer on screen
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func dismissKeyboard() {
// Dismiss keyboard for textfield
self.tView.resignFirstResponder()
}
}
note.swift
import UIKit
var allNotes:[Note] = []
var currentNoteIndex:NSInteger = -1
var noteTable:UITableView?
let KAllNotes:String = "notes"
class Note: NSObject {
var date:String
var note:String
override init() {
date = NSDate().description
note = ""
}
func dictionary() -> NSDictionary {
return ["note":note, "date":date]
}
class func saveNotes() {
var aDictionaries:[NSDictionary] = []
for (var i:NSInteger = 0; i < allNotes.count; i++) {
aDictionaries.append(allNotes[i].dictionary())
}
NSUserDefaults.standardUserDefaults().setObject(aDictionaries, forKey: KAllNotes)
// aDictionaries.writeToFile(filePath(), atomically: true)
}
class func loadnotes() {
allNotes.removeAll(keepCapacity: true)
var defaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var savedData:[NSDictionary]? = defaults.objectForKey(KAllNotes) as? [NSDictionary]
// var savedData:NSArray? = NSArray(contentsOfFile: filePath())
if let data:[NSDictionary] = savedData {
for (var i:NSInteger = 0; i < data.count; i++) {
var n:Note = Note()
n.setValuesForKeysWithDictionary(data[i] as [NSObject : AnyObject])
allNotes.append(n)
}
}
}
class func filePath() -> String {
var d:[String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if let directories:[String] = d {
var docsDirectory:String = directories[0]
var path:String = docsDirectory.stringByAppendingPathComponent("\(KAllNotes).notes")
return path;
}
return ""
}
}
Thanks in advance
Sam
Add an NSUserDefault boolean that stores whether or not the initial note should be shown, e.g. that the app has been launched for the first time. Then load an initial note accordingly. When a note is added or the initial note is deleted, then change the boolean accordingly so the initial note doesn't show up next time.
You could also initialize your database with an initial note. Not clear from your code how the notes are saved, but this approach would probably rely on the NSUserDefault approach above, except it could be done in the AppDelegate or something.
example:
let InitialSetupComplete = "InitialSetupComplete" // Note: I would define this at the top of a file
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.boolForKey(InitialSetupComplete) {
// Show initial note
}
// Later on when the note is deleted, or modified (or immediately after initial note loaded into the database, see below)
defaults.setBool(true, forKey: InitialSetupComplete)
Would be easier/cleaner just to initialize your database with the initial note in the app delegate (e.g. call within applicationDidFinishLaunching), so your view controller doesn't have to figure this out. Similar code, except you would use setBool right away after the initial note has been saved to the database. I don't know anything about your database from the question, so can't really provide a more detailed example than this. Hope this helps.
I would like to have an autocomplete textfield that autocompletes locations for me like the one for android:
https://developers.google.com/places/training/autocomplete-android
Does anyone know where I can find a tutorial for this or an example?
Thanks!
Steps :
Add the Alamofire CocoaPods in your swift project.
Find your Google place API key on Google APIs Console.
Add following code
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let gpaViewController = GooglePlacesAutocomplete(
apiKey: "YOUR GOOGLE PLACE API KEY",
placeType: .Address
)
gpaViewController.placeDelegate = self
presentViewController(gpaViewController, animated: true, completion: nil)
}
}
extension ViewController: GooglePlacesAutocompleteDelegate {
func placeSelected(place: Place) {
println(place.description)
}
func placeViewClosed() {
dismissViewControllerAnimated(true, completion: nil)
}
}
GooglePlacesAutocomplete.swift
import UIKit
import Alamofire
enum PlaceType: Printable {
case All
case Geocode
case Address
case Establishment
case Regions
case Cities
var description : String {
switch self {
case .All: return ""
case .Geocode: return "geocode"
case .Address: return "address"
case .Establishment: return "establishment"
case .Regions: return "regions"
case .Cities: return "cities"
}
}
}
struct Place {
let id: String
let description: String
}
protocol GooglePlacesAutocompleteDelegate {
func placeSelected(place: Place)
func placeViewClosed()
}
// MARK: - GooglePlacesAutocomplete
class GooglePlacesAutocomplete: UINavigationController {
var gpaViewController: GooglePlacesAutocompleteContainer?
var placeDelegate: GooglePlacesAutocompleteDelegate? {
get { return gpaViewController?.delegate }
set { gpaViewController?.delegate = newValue }
}
convenience init(apiKey: String, placeType: PlaceType = .All) {
let gpaViewController = GooglePlacesAutocompleteContainer(
apiKey: apiKey,
placeType: placeType
)
self.init(rootViewController: gpaViewController)
self.gpaViewController = gpaViewController
let closeButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: "close")
gpaViewController.navigationItem.leftBarButtonItem = closeButton
gpaViewController.navigationItem.title = "Enter Address"
}
func close() {
placeDelegate?.placeViewClosed()
}
}
// MARK: - GooglePlaceSearchDisplayController
class GooglePlaceSearchDisplayController: UISearchDisplayController {
override func setActive(visible: Bool, animated: Bool) {
if active == visible { return }
searchContentsController.navigationController?.navigationBarHidden = true
super.setActive(visible, animated: animated)
searchContentsController.navigationController?.navigationBarHidden = false
if visible {
searchBar.becomeFirstResponder()
} else {
searchBar.resignFirstResponder()
}
}
}
// MARK: - GooglePlacesAutocompleteContainer
class GooglePlacesAutocompleteContainer: UIViewController {
var delegate: GooglePlacesAutocompleteDelegate?
var apiKey: String?
var places = [Place]()
var placeType: PlaceType = .All
convenience init(apiKey: String, placeType: PlaceType = .All) {
self.init(nibName: "GooglePlacesAutocomplete", bundle: nil)
self.apiKey = apiKey
self.placeType = placeType
}
override func viewDidLoad() {
super.viewDidLoad()
let tv: UITableView? = searchDisplayController?.searchResultsTableView
tv?.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
}
// MARK: - GooglePlacesAutocompleteContainer (UITableViewDataSource / UITableViewDelegate)
extension GooglePlacesAutocompleteContainer: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.searchDisplayController?.searchResultsTableView?.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
// Get the corresponding candy from our candies array
let place = self.places[indexPath.row]
// Configure the cell
cell.textLabel.text = place.description
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
delegate?.placeSelected(self.places[indexPath.row])
}
}
// MARK: - GooglePlacesAutocompleteContainer (UISearchDisplayDelegate)
extension GooglePlacesAutocompleteContainer: UISearchDisplayDelegate {
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
getPlaces(searchString)
return false
}
private func getPlaces(searchString: String) {
Alamofire.request(.GET,
"https://maps.googleapis.com/maps/api/place/autocomplete/json",
parameters: [
"input": searchString,
"type": "(\(placeType.description))",
"key": apiKey ?? ""
]).responseJSON { request, response, json, error in
if let response = json as? NSDictionary {
if let predictions = response["predictions"] as? Array<AnyObject> {
self.places = predictions.map { (prediction: AnyObject) -> Place in
return Place(
id: prediction["id"] as String,
description: prediction["description"] as String
)
}
}
}
self.searchDisplayController?.searchResultsTableView?.reloadData()
}
}
}
GooglePlacesAutocomplete.xib
Hope this will help others.
Here's full updated code for Google Autocomplete place API.
Xcode 10.0 & Swift 4.2
Follow this link as to Get Google API KEY.
After Getting the API KEY
Install Cocoa Pods:
source 'https://github.com/CocoaPods/Specs.git'
target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
pod 'GooglePlaces'
pod 'GooglePlacePicker'
pod 'GoogleMaps'
end
Appdelegate File:
import UIKit
import GooglePlaces
let GOOGLE_API_KEY = "AIzaSyCuZkL7bh_hIDggnJob-b0cDueWlvRgpck"
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GMSPlacesClient.provideAPIKey(GOOGLE_API_KEY)
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
ViewController File:
import UIKit
import GooglePlaces
class ViewController: UIViewController ,CLLocationManagerDelegate{
var placesClient: GMSPlacesClient!
// Add a pair of UILabels in Interface Builder, and connect the outlets to these variables.
#IBOutlet var nameLabel: UILabel!
#IBOutlet var addressLabel: UILabel!
let locationManager = CLLocationManager()
var resultsViewController: GMSAutocompleteResultsViewController?
var searchController: UISearchController?
var resultView: UITextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
if CLLocationManager.authorizationStatus() == .notDetermined
{
locationManager.requestAlwaysAuthorization()
}
placesClient = GMSPlacesClient.shared()
// self.addToNavbar()
// self.addToSubview()
self.addToPopover()
}
func addToNavbar(){
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
// Put the search bar in the navigation bar.
searchController?.searchBar.sizeToFit()
navigationItem.titleView = searchController?.searchBar
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
// Prevent the navigation bar from being hidden when searching.
searchController?.hidesNavigationBarDuringPresentation = false
}
func addToSubview(){
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
let subView = UIView(frame: CGRect(x: 0, y: 65.0, width: 350.0, height: 45.0))
subView.addSubview((searchController?.searchBar)!)
view.addSubview(subView)
searchController?.searchBar.sizeToFit()
searchController?.hidesNavigationBarDuringPresentation = false
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
}
func addToPopover(){
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
// Add the search bar to the right of the nav bar,
// use a popover to display the results.
// Set an explicit size as we don't want to use the entire nav bar.
searchController?.searchBar.frame = (CGRect(x: 0, y: 0, width: 250.0, height: 44.0))
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: (searchController?.searchBar)!)
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
definesPresentationContext = true
// Keep the navigation bar visible.
searchController?.hidesNavigationBarDuringPresentation = false
searchController?.modalPresentationStyle = .popover
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)
{
print(status)
}
// Add a UIButton in Interface Builder, and connect the action to this function.
#IBAction func getCurrentPlace(_ sender: UIButton) {
placesClient.currentPlace(callback: { (placeLikelihoodList, error) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
self.nameLabel.text = "No current place"
self.addressLabel.text = ""
if let placeLikelihoodList = placeLikelihoodList {
print("placeLikelihoodList -- \(placeLikelihoodList)")
let place = placeLikelihoodList.likelihoods.first?.place
if let place = place {
self.nameLabel.text = place.name
self.addressLabel.text = place.formattedAddress?.components(separatedBy: ", ")
.joined(separator: "\n")
print(place.name)
print(place.coordinate)
print(place.placeID)
print(place.phoneNumber)
print(place.formattedAddress ?? "")
}
}
})
}
}
//MARK: Extentions
// Handle the user's selection.
extension ViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didAutocompleteWith place: GMSPlace) {
searchController?.isActive = false
// Do something with the selected place.
print("Place name: \(place.name)")
print("Place address: \(String(describing: place.formattedAddress))")
print("Place attributions: \(place.attributions)")
}
func resultsController(_ resultsController: GMSAutocompleteResultsViewController,
didFailAutocompleteWithError error: Error){
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
Lightweight Solution!
Instead of using Google framework and Third party library to make simple requests I created a simple library where you can Make a number of Google api requests like Google Autocomplete, Google ReverseGeo , Place Information and Path api for getting path between two location.
To use the library all you have to do is
step-1 Import GoogleApiHelper into your project.
step-2 Initialise GoogleApiHelper
GoogleApi.shared.initialiseWithKey("API_KEY")
step-3 Call the methods
var input = GInput()
input.keyword = "San francisco"
GoogleApi.shared.callApi(input: input) { (response) in
if let results = response.data as? [GApiResponse.Autocomplete], response.isValidFor(.autocomplete) {
//Enjoy the Autocomplete Api
} else { print(response.error ?? "ERROR") }
}
You can find the library here
Using Alamofire get the autocomplete Google places result from data, you can show it in table view cell
plist configuration
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Code
import UIKit
import Alamofire
class GooglePlacesViewController: UIViewController,UISearchBarDelegate,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var srchLocation: UISearchBar!
#IBOutlet weak var tblLoction: UITableView!
var arrPlaces = NSMutableArray(capacity: 100)
let operationQueue = OperationQueue()
let currentLat = 51.5033640
let currentLong = -0.1276250
var LocationDataDelegate : LocationData! = nil
var tblLocation : UITableView!
var lblNodata = UILabel()
override func viewDidLoad()
{
super.viewDidLoad()
lblNodata.frame = CGRect(x: 0, y: 80, width:
self.view.frame.size.width, height: self.view.frame.size.height-60)
lblNodata.text = "Please enter text to get your location"
self.view.addSubview(lblNodata)
srchLocation.placeholder = "Ente your location details"
lblNodata.textAlignment = .center
srchLocation.delegate = self
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.beginSearching(searchText: searchText)
}
func beginSearching(searchText:String) {
if searchText.characters.count == 0 {
self.arrPlaces.removeAllObjects()
tblLoction.isHidden = true
lblNodata.isHidden = false
return
}
operationQueue.addOperation { () -> Void in
self.forwardGeoCoding(searchText: searchText)
}
}
//MARK: - Search place from Google -
func forwardGeoCoding(searchText:String) {
googlePlacesResult(input: searchText) { (result) -> Void in
let searchResult:NSDictionary = ["keyword":searchText,"results":result]
if result.count > 0
{
let features = searchResult.value(forKey: "results") as! NSArray
self.arrPlaces = NSMutableArray(capacity: 100)
print(features.count)
for jk in 0...features.count-1
{
let dict = features.object(at: jk) as! NSDictionary
self.arrPlaces.add(dict)
}
DispatchQueue.main.async(execute: {
if self.arrPlaces.count != 0
{
self.tblLoction.isHidden = false
self.lblNodata.isHidden = true
self.tblLoction.reloadData()
}
else
{
self.tblLoction.isHidden = true
self.lblNodata.isHidden = false
self.tblLoction.reloadData()
}
});
}
}
}
//MARK: - Google place API request -
func googlePlacesResult(input: String, completion: #escaping (_ result: NSArray) -> Void) {
let searchWordProtection = input.replacingOccurrences(of: " ", with: ""); if searchWordProtection.characters.count != 0 {
let urlString = NSString(format: "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&types=establishment|geocode&location=%#,%#&radius=500&language=en&key= your key",input,"\(currentLocationLatitude)","\(currentLocationLongtitude)")
print(urlString)
let url = NSURL(string: urlString.addingPercentEscapes(using: String.Encoding.utf8.rawValue)!)
print(url!)
let defaultConfigObject = URLSessionConfiguration.default
let delegateFreeSession = URLSession(configuration: defaultConfigObject, delegate: nil, delegateQueue: OperationQueue.main)
let request = NSURLRequest(url: url! as URL)
let task = delegateFreeSession.dataTask(with: request as URLRequest, completionHandler:
{
(data, response, error) -> Void in
if let data = data
{
do {
let jSONresult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String:AnyObject]
let results:NSArray = jSONresult["predictions"] as! NSArray
let status = jSONresult["status"] as! String
if status == "NOT_FOUND" || status == "REQUEST_DENIED"
{
let userInfo:NSDictionary = ["error": jSONresult["status"]!]
let newError = NSError(domain: "API Error", code: 666, userInfo: userInfo as [NSObject : AnyObject])
let arr:NSArray = [newError]
completion(arr)
return
}
else
{
completion(results)
}
}
catch
{
print("json error: \(error)")
}
}
else if let error = error
{
print(error)
}
})
task.resume()
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrPlaces.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let tblCell = tableView.dequeueReusableCell(withIdentifier: "locationCell")
let dict = arrPlaces.object(at: indexPath.row) as! NSDictionary
tblCell?.textLabel?.text = dict.value(forKey: "description") as? String
tblCell?.textLabel?.numberOfLines = 0
tblCell?.textLabel?.sizeToFit()
return tblCell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if LocationDataDelegate != nil
{
let dict = arrPlaces.object(at: indexPath.row) as! NSDictionary
print(dict.value(forKey: "terms") as! NSArray)
let ArrSelected = dict.value(forKey: "terms") as! NSArray
LocationDataDelegate.didSelectLocationData(LocationData: ArrSelected)
}
self.dismiss(animated: true, completion: nil)
}
}
class AddNewAddressVC: UIViewController,UITextFieldDelegate{
func autocompleteClicked() {
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = self
// Specify the place data types to return.
let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue))!
autocompleteController.placeFields = fields
// Specify a filter.
let filter = GMSAutocompleteFilter()
filter.type = .address
autocompleteController.autocompleteFilter = filter
// Display the autocomplete view controller.
present(autocompleteController, animated: true, completion: nil)
}
#IBAction func action_selectGooglePlaces(_ sender: UIButton) {
autocompleteClicked()
}
}
extension AddNewAddressVC: GMSAutocompleteViewControllerDelegate {
// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
print("Place name: \(place.name)")
print("Place ID: \(place.placeID)")
print("Place attributions: \(place.attributions)")
dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// User canceled the operation.
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
dismiss(animated: true, completion: nil)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}