Two textfield displays same GMSPlace Autocomplete - ios

Im my GMSAUtocompleteController I have two textfield but they display same location when clicked
extension RideAddDetailsViewController: GMSAutocompleteViewControllerDelegate {
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
locationTextField.text = place.name
destinationTextField.text = place.name
dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
// Handle the error
print("Error: ", error.localizedDescription)
}
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
// Dismiss when the user canceled the action
dismiss(animated: true, completion: nil)
}

You can use tag to separate them.
if textField.isEqual(locationTextField)
{
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.view.tag = 1 // assign the tag you want
autocompleteController.delegate = self
present(autocompleteController, animated: true, completion: nil)
}
else if textField.isEqual(destinationTextField)
{
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.view.tag = 2 // assign the tag you want
autocompleteController.delegate = self
present(autocompleteController, animated: true, completion: nil)
}
Now you can separate the value from delegate method like this and assign to the textfield.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
if viewController.view.tag == 1
{
locationTextField.text = place.name
}
else viewController.view.tag == 2
{
destinationTextField.text = place.name
}
dismiss(animated: true, completion: nil)
}

I set the reference of clicked textField to selectedTextField in both my IBActions.
var selectedTextField = UITextField()
#IBAction func locationTextFieldTapped(_ sender: Any) {
selectedTextField = locationTextField
//locationTextField.resignFirstResponder()
let autoCompleteController = GMSAutocompleteViewController()
locationTextField.tag = 0
autoCompleteController.delegate = self
present(autoCompleteController, animated: true, completion: nil)
}
#IBAction func destinationTextField(_ sender: Any) {
selectedTextField = destinationTextField
//destinationTextField.resignFirstResponder()
let autoCompleteController = GMSAutocompleteViewController()
destinationTextField.tag = 1
autoCompleteController.delegate = self
present(autoCompleteController, animated: true, completion: nil)
}
Then in the GMSAutocompleteViewControllerDelegate
I did this:
self.selectedTextField.text = place.name

Related

Back button does not work in Navigation Controller

I try to implement a back button for my controllers.
My Navigation Controller implementation inside of the Container Controller:
func configureMainController(){
let mainController = MainController()
mainController.delegate = self
mainController.backDelegate = self
centerController = UINavigationController(rootViewController: mainController)
view.addSubview(centerController.view)
addChild(centerController)
centerController.didMove(toParent: self)
}
My Back Delegate:
extension ContainerController: BackDelegate {
func handleBack() {
print("ok")
centerController.navigationController?.popViewController(animated: true)
}
}
Back button inside of the Main Controller:
navigationItem.rightBarButtonItem = UIBarButtonItem(image: image2?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(backAction))
#objc func backAction() -> Void {
backDelegate?.handleBack()
}
How I push the Controller that I need to pop:
DispatchQueue.main.async {
let vc = ScienceController(collectionViewLayout: UICollectionViewFlowLayout())
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
Here is my Main Controller with relevant functions:
class MainController: UIViewController {
let tabBarCnt = UITabBarController()
var delegate: MainControllerDelegate?
var backDelegate: BackDelegate?
override func viewDidLoad() {
super.viewDidLoad()
createTabBarController()
}
#objc func backAction() -> Void {
//self.navigationController?.popViewController(animated: true)
backDelegate?.handleBack()
}
func checkIfUserIsLoggedIn(){
if Auth.auth().currentUser?.uid == nil{
performSelector(inBackground: #selector(handleLogout), with: nil)
}
}
#objc func handleLogout(){
do {
try Auth.auth().signOut()
} catch let logoutError {
print(logoutError)
}
DispatchQueue.main.async {
// UIView usage
let loginController = LoginController()
loginController.mainController = self
loginController.modalPresentationStyle = .fullScreen
self.present(loginController, animated: true, completion: nil)
}
}
func createTabBarController() {
let firstVc = Controller1()
firstVc.title = "vc1"
firstVc.view.backgroundColor = UIColor.white
firstVc.tabBarItem = UITabBarItem.init(title: "vc1", image: nil, tag: 0)
let secondVc = Controller2()
secondVc.title = "vc2"
secondVc.view.backgroundColor = UIColor.white
secondVc.tabBarItem = UITabBarItem.init(title: "vc2", image: nil, tag: 1)
let thirdVc = Controller3()
thirdVc.title = "vc3"
thirdVc.view.backgroundColor = UIColor.white
thirdVc.tabBarItem = UITabBarItem.init(title: "vc3", image: nil, tag: 2)
let controllerArray = [firstVc, secondVc, thirdVc]
tabBarCnt.viewControllers = controllerArray.map{
UINavigationController.init(rootViewController: $0)}
//tabBarCnt.selectedIndex = 1
self.view.addSubview(tabBarCnt.view)
}
}
Here is my Container Controller:
class ContainerController: UIViewController {
// MARK: - Properties
var menuController: MenuController!
var centerController: UINavigationController!
var isExpanded = false
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
configureMainController()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .darkContent
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .slide
}
override var prefersStatusBarHidden: Bool{
return isExpanded
}
// MARK: - Handlers
func configureMainController(){
let mainController = MainController()
mainController.delegate = self
mainController.backDelegate = self
centerController = UINavigationController(rootViewController: mainController)
view.addSubview(centerController.view)
addChild(centerController)
centerController.didMove(toParent: self)
}
func configureMenuController(){
if menuController == nil{
menuController = MenuController()
menuController.delegate = self
view.insertSubview(menuController.view, at: 0)
addChild(menuController)
menuController.didMove(toParent: parent.self)
}
}
func animatePanel(shouldExpand: Bool, menuOption: MenuOption?){
if shouldExpand{
//show
UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseInOut, animations: {
self.centerController.view.frame.origin.x = self.centerController.view.frame.width - 80
}, completion: nil)
}
else{
//hide
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseInOut, animations: {
self.centerController.view.frame.origin.x = 0
}) { (_) in
guard let menuOption = menuOption else {return}
self.didSelectMenuOption(menuOption: menuOption)
}
}
animateStatusBar()
}
func didSelectMenuOption(menuOption: MenuOption){
switch menuOption {
case .Profile:
let controller = ProfileController()
present(UINavigationController(rootViewController: controller), animated: true, completion: nil)
case .Settings:
let controller = SettingsController()
//controller.username = "pasha"
present(UINavigationController(rootViewController: controller), animated: true, completion: nil)
case .Logout:
handleLogout()
}
}
func animateStatusBar(){
UIView.animate(withDuration: 0.5, delay: 0.0, options: .curveEaseInOut, animations: {
self.setNeedsStatusBarAppearanceUpdate()
}, completion: nil)
}
#objc func handleLogout(){
do{
try Auth.auth().signOut()
DispatchQueue.main.async {
UIApplication.shared.keyWindow?.rootViewController = LoginController()
}
//UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)
} catch let logoutError {
print(logoutError)
}
}
}
extension ContainerController: MainControllerDelegate {
func handleMenuToggle(forMenuOption menuOption: MenuOption?) {
if !isExpanded {
configureMenuController()
}
isExpanded = !isExpanded
animatePanel(shouldExpand: isExpanded, menuOption: menuOption)
}
}
extension ContainerController: BackDelegate {
func handleBack() {
print("ok")
centerController.popViewController(animated: true)
}
}
The print("ok") statement works but not centerController.navigationController?.popViewController(animated: true). I also tried self.navigationController?.popViewController(animated: true) and It does not work too...
Since UINavigationController is subclass of UIViewController it has navigationController property on it. You should not be using navigationController property present on UINavigationController. So your code should be
centerController.popViewController(animated: true)
Edit:
As "Sylvan D Ash" mentioned you are pushing and popping from 2 different controllers.
self.navigationController?.pushViewController(vc, animated: true)
need to be replaced with
centerController.pushViewController(vc, animated: true)

MFMailComposeViewController doesn't read variable into message in Swift

I have small problem. I'm using MFMailComposeViewController to send email after work. So I have var allRuns, and I've printed that var in few places, and it always show value = 3. But in my MailViewController into MessageBody it's equal 0/nil (I've set 0). If it is important- I'm taking var from Firebase, but earlier in the app. Where should I seek problem? That's some code below.
MailViewController:
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let av = ActualValues()
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - Buttons
#IBAction func emailButtonTapped(_ sender: UIButton) {
showMailComposer()
}
#IBAction func backButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
//MARK: -Func
func showMailComposer() {
if MFMailComposeViewController.canSendMail() {
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["paereson#gmail.com"])
mailComposer.setSubject("Work of \(av.currentDate())")
mailComposer.setMessageBody("All runs: \(av.allRuns)", isHTML: false)
present(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
if let _ = error {
//show alert
controller.dismiss(animated: true, completion: nil)
return
}
switch result {
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
case .saved:
print("saved")
case .sent:
print("Email sent")
#unknown default:
print("default")
}
controller.dismiss(animated: true, completion: nil)
}
}
Few lines in av = ActualValuse:
var allRuns: Int = 0
var runs: Array? = []
//All runs
func allRunsFunc() {
let ref1 = ref.child("\(currentYear())/\(currentMonth())/\(currentDay())")
ref1.observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
self.allRuns = snapshots.count as Int
}
}
}
EDIT:
Should I use segue before MFMAilComposeViewController? If yes, how should I configure it?
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let av = ActualValues()
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - Buttons
#IBAction func emailButtonTapped(_ sender: UIButton) {
showMailComposer()
}
#IBAction func backButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
//MARK: -Func
func showMailComposer() {
if MFMailComposeViewController.canSendMail() {
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["paereson#gmail.com"])
mailComposer.setSubject("Work of \(av.currentDate())")
mailComposer.setMessageBody("\(av.exportText())", isHTML: true)
present(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
if let _ = error {
//show alert
controller.dismiss(animated: true, completion: nil)
return
}
switch result {
case .cancelled:
print("Cancelled")
case .failed:
print("Failed")
case .saved:
print("saved")
case .sent:
print("Email sent")
#unknown default:
print("default")
}
controller.dismiss(animated: true, completion: nil)
}
func configureMail(model: ActualValues) {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is MFMailComposeViewController {
let vc = segue.destination as? MFMailComposeViewController
vc?.configureMail(model: av)
}
}
}
You seem to be missing the execution of allRunsFunc function. Maybe call it in the ActualValue init method.

move pageViewController with button

Basically I'd like to move my PageViewController not only with swipe but also with buttons.
#IBAction func nextButtonAction(_ sender: Any){
}
My PageViewController looks like in this guide
What I have:
PageViewController
3 Viewcontrollers
Sorry if it's a duplicate didn't found exactly same situation
tried to call UIPageViewControllerDataSource on each ViewController
but didn't work also I think this is not the best approach
Edited:
This is my PageViewController
class PageVC: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
lazy var VCarr: [UIViewController] = {
return [self.VCInstance(name: "signUpVerification"),
self.VCInstance(name: "signUpVerification1"),
self.VCInstance(name: "signUpVerification2"),
]
}()
func VCInstance(name:String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier:name)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
if let firsVC = VCarr.first {
setViewControllers([firsVC], direction: .forward, animated: true, completion: nil)
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCarr.index(of: viewController) else { return nil }
let previousIndex = viewControllerIndex - 1
guard previousIndex >= 0 else {
return nil
}
return VCarr[previousIndex]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = VCarr.index(of: viewController) else { return nil }
let nextIndex = viewControllerIndex + 1
guard nextIndex < VCarr.count else {
return nil
}
return VCarr[nextIndex]
}
}
extension PageVC {
func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
if let currentViewController = VCarr.first {
if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) //for some reasons there's nil {
setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
}
}
}
}
this is Viewcontroller where I call it:
var pageVC = PageVC()
#IBAction func nextButtonAction(_ sender: Any){
pageVC.goToNextPage()
}
Solution:
YourViewController: {
#IBAction func nextButtonAction(_ sender: Any){
let pageViewController = self.parent as! PageVC
pageViewController.nextPageWithIndex(index: 1)
}
}
PageViewController: {
func nextPageWithIndex(index: Int) {
setViewControllers([VCarr[index]], direction: .forward, animated: true, completion: nil)
}
}
To move page viewController to by button click you can achieve very simply by using following extension
extension UIPageViewController {
func goToNextPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
if let currentViewController = viewControllers?[0] {
if let nextPage = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) {
setViewControllers([nextPage], direction: .forward, animated: animated, completion: completion)
}
}
}
func goToPreviousPage(animated: Bool = true, completion: ((Bool) -> Void)? = nil) {
if let currentViewController = viewControllers?[0] {
if let previousPage = dataSource?.pageViewController(self, viewControllerBefore: currentViewController){
setViewControllers([previousPage], direction: .reverse, animated: true, completion: completion)
}
}
}
}
To move forward
self.pageViewController.goToNextPage()
To move backward
self.pageViewController.goToPreviousPage()
don't forget to check whether the index available or not
for example:
if pageArray.count > currentIdex {
self.pageViewController.goToNextPage()
}
Hope this will help you
Try adding this method in your button Action for moving from first View Controller to second:
self.pageViewController.setViewControllers([self.viewControllerAtIndex(1)!], direction: .forward, animated: true, completion: nil)
pageControl2.currentPage = 1
Rest you can add your current PageTracker using PageControl.
self.pageViewController.setViewControllers([self.viewControllerAtIndex(pageControl.currentPage + 1)!], direction: .forward, animated: true, completion: nil)
pageControl.currentPage += 1

Change text field background color on UISearchBar with GoogleMaps API

Is there anyway to change text field background color on UISearchBar?
this is the picture
Here's my code :
This is action function when the button clicked
func streetButtonOnPressed(){
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.tableCellBackgroundColor = .white
autocompleteController.delegate = self
UINavigationBar.appearance().barTintColor = .primary
UINavigationBar.appearance().tintColor = .white
let filter = GMSAutocompleteFilter()
filter.type = .establishment
filter.country = "SG"
autocompleteController.autocompleteFilter = filter
present(autocompleteController, animated: true, completion: nil)
}
Here's the extension :
extension ManageListingsCreateListingPropertyLocationViewController : GMSAutocompleteViewControllerDelegate {
// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
print("Place name: \(place.name)")
print("Place address: \(place.formattedAddress)")
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
}}
Is there anyway to solve this ? T.T

There's a bug in CNContactPickerController

After spending all day (>12 hours) trying to isolate a bug in 13 lines of mind-bogglingly generic code, I have come to the dubious conclusion that there must be a bug in the current iteration of CNContactPickerViewController, in iOS 9.2.
Simply copy+paste this ViewController and link the invite action to a button.
The bug is that MFMessageComposeViewController dismisses itself immediately.
If anybody knows what to do with this, do share?
import UIKit
import MessageUI
import ContactsUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate, CNContactPickerDelegate {
let contactPickerVC = CNContactPickerViewController()
let messageVC = MFMessageComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
contactPickerVC.delegate = self
}
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.messageComposeDelegate = self
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
picker.presentViewController(messageVC, animated: true, completion: nil)
}
}
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func invite(sender: AnyObject) {
presentViewController(contactPickerVC, animated: true, completion: nil)
}
}
I got it working by dismissing the pickerVC and changing the controller which presents the messageVC!
Insert (before the messageVC config lines):
picker.dismissViewControllerAnimated(true, completion: nil)
Replace
picker.presentViewController(messageVC, animated: true, completion: nil)
with
presentViewController(messageVC, animated: true, completion: nil)

Resources