Search code examples
iosswiftfirebaseuipickerview

UIPickerView for each text field with different arrays (Swift/Firebase)


I am trying to create a form in which each text field has a UIPickerView which the user can use to select the option needed. I need a to use a different array of information for each text field but I can't seem to get it to work and I have been stuck on it for quite a while now.

I have had a method which was possibly working but I couldn't then retrieve the data from the text field for Firebase due to each field having the same name.

Here is my code so far, this is the latest method that I have tried that doesn't work:

import UIKit
import Firebase
import FirebaseDatabase

class CreatePostViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate {

@IBOutlet weak var gameTextField: UITextField!
@IBOutlet weak var activityTextField: UITextField!
@IBOutlet weak var consoleTextField: UITextField!
@IBOutlet weak var skillTextField: UITextField!
@IBOutlet weak var communicationTextField: UITextField!
@IBOutlet weak var lfglfmTextField: UITextField!
@IBOutlet weak var rulesTextView: UITextView!
@IBOutlet weak var descriptionTextView: UITextView!

var games = ["Assassin's Creed Origins", "Battlefield 1", "Call of Duty: Advanced Warfare", "Call of Duty: Black Ops III", "Call of Duty: Ghosts", "Call of Duty: Infinite Warfare", "Call of Duty: Modern Warfare Remastered", "Call of Duty: WWII", "Destiny", "Destiny 2", "Fifa 16", "Fifa 17", "Fifa 18", "Rocket League"]
var console = ["Xbox One", "Xbox 360", "Playstation 4", "Playstation 3"]
var skill = ["Achiever", "Explorer", "Killer", "Socializer"]
var communication = ["Mic", "No Mic"]
var lfglfm = ["LFG", "LFM"]

var itemSelected = ""

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    //remove margin / padding from textview
    self.rulesTextView.textContainerInset = .zero
    self.rulesTextView.contentInset = UIEdgeInsetsMake(0, -5, 0, 0)
//        self.descriptionTextView.textContainerInset = .zero
//        self.descriptionTextView.contentInset = UIEdgeInsetsMake(0, -5, 0, 0)

    //allow tap on screen to remove text field input from screen
    self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))

    //UIPICKER
    let pickerView = UIPickerView()
    pickerView.delegate = self
    pickerView.dataSource = self

    gameTextField.inputView = pickerView
    consoleTextField.inputView = pickerView
    skillTextField.inputView = pickerView
    communicationTextField.inputView = pickerView
    lfglfmTextField.inputView = pickerView

    updatePicker()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//update pickerView
func updatePicker(){
    let pickerView = UIPickerView()
    pickerView.reloadAllComponents()
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if gameTextField.isFirstResponder{
        return games.count
    }else if consoleTextField.isFirstResponder{
        return console.count
    }else if skillTextField.isFirstResponder{
        return skill.count
    }else if communicationTextField.isFirstResponder{
        return communication.count
    }else if lfglfmTextField.isFirstResponder{
        return lfglfm.count
    }
}

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
    if gameTextField.isFirstResponder{
        return games[row]
    }else if consoleTextField.isFirstResponder{
        return console[row]
    }else if skillTextField.isFirstResponder{
        return skill[row]
    }else if communicationTextField.isFirstResponder{
        return communication[row]
    }else if lfglfmTextField.isFirstResponder{
        return lfglfm[row]
    }
}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if gameTextField.isFirstResponder{
        let itemselected = games[row]
        gameTextField.text = itemselected
    }else if consoleTextField.isFirstResponder{
        let itemselected = console[row]
        consoleTextField.text = itemselected
    }else if skillTextField.isFirstResponder{
        let itemselected = skill[row]
        skillTextField.text = itemselected
    }else if communicationTextField.isFirstResponder{
        let itemselected = communication[row]
        communicationTextField.text = itemselected
    }else if lfglfmTextField.isFirstResponder{
        let itemselected = lfglfm[row]
        lfglfmTextField.text = itemselected
    }
}


@IBAction func createPostTapped(_ sender: UIButton) {
    if let uid = Auth.auth().currentUser?.uid {
        Database.database().reference().child("usernames").child(uid).observeSingleEvent(of: .value, with: {
            (snapshot) in
            if let userDictionary = snapshot.value as? [String: AnyObject] {
                for user in userDictionary {
                    if let username = user.value as? String {
                        if let game = self.gameTextField.text {
                            if let activity = self.activityTextField.text {
                                if let console = self.consoleTextField.text {
                                    if let skill = self.skillTextField.text {
                                        if let communication = self.communicationTextField.text {
                                            if let lfglfm = self.lfglfmTextField.text {
                                                if let description = self.descriptionTextView.text {

                                                    let postObject: Dictionary<String, Any> = [
                                                        "uid" : uid,
                                                        "username" : username,
                                                        "game" : game,
                                                        "activity" : activity,
                                                        "console" : console,
                                                        "skill" : skill,
                                                        "communication" : communication,
                                                        "lfglfm" : lfglfm,
                                                        "description" : description
                                                        ]

                                                    Database.database().reference().child("posts").childByAutoId().setValue(postObject)

                                                    let alert = UIAlertController(title: "Success!", message: "Your post was added successfully.", preferredStyle: .alert)
                                                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
                                                        //code will run when ok button is pressed
                                                        let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoggedInVC")
                                                        self.present(vc!, animated: true, completion: nil)
                                                    }))
                                                    self.present(alert, animated: true, completion: nil)

                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        })
    }
}



/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

If anyone knows of a successful method which I can implement please feel free contribute it would be much appreciated.

Thank you.


Solution

  • Your code is almost right. I would just store a class attribute with the UIPickerView so you can reload the components upon textField editing status change. For that purpose, you have also to set the textField delegates.

    Here a working example with the adjustments I just commented:

    import UIKit
    
    class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate {
    
    
        @IBOutlet weak var gameTextField: UITextField!
        @IBOutlet weak var activityTextField: UITextField!
        @IBOutlet weak var consoleTextField: UITextField!
        @IBOutlet weak var skillTextField: UITextField!
        @IBOutlet weak var communicationTextField: UITextField!
        @IBOutlet weak var lfglfmTextField: UITextField!
    
        var games = ["Assassin's Creed Origins", "Battlefield 1", "Call of Duty: Advanced Warfare", "Call of Duty: Black Ops III", "Call of Duty: Ghosts", "Call of Duty: Infinite Warfare", "Call of Duty: Modern Warfare Remastered", "Call of Duty: WWII", "Destiny", "Destiny 2", "Fifa 16", "Fifa 17", "Fifa 18", "Rocket League"]
        var console = ["Xbox One", "Xbox 360", "Playstation 4", "Playstation 3"]
        var skill = ["Achiever", "Explorer", "Killer", "Socializer"]
        var communication = ["Mic", "No Mic"]
        var lfglfm = ["LFG", "LFM"]
    
        var itemSelected = ""
    
        weak var pickerView: UIPickerView?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
    
            //remove margin / padding from textview
            //        self.descriptionTextView.textContainerInset = .zero
            //        self.descriptionTextView.contentInset = UIEdgeInsetsMake(0, -5, 0, 0)
    
            //allow tap on screen to remove text field input from screen
            self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
    
            //UIPICKER
            let pickerView = UIPickerView()
            pickerView.delegate = self
            pickerView.dataSource = self
    
            gameTextField.delegate = self
            consoleTextField.delegate = self
            skillTextField.delegate = self
            communicationTextField.delegate = self
            lfglfmTextField.delegate = self
    
            gameTextField.inputView = pickerView
            consoleTextField.inputView = pickerView
            skillTextField.inputView = pickerView
            communicationTextField.inputView = pickerView
            lfglfmTextField.inputView = pickerView
    
            //It is important that goes after de inputView assignation
            self.pickerView = pickerView
    
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        func textFieldDidBeginEditing(_ textField: UITextField) {
            self.pickerView?.reloadAllComponents()
        }
    
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            if gameTextField.isFirstResponder{
                return games.count
            }else if consoleTextField.isFirstResponder{
                return console.count
            }else if skillTextField.isFirstResponder{
                return skill.count
            }else if communicationTextField.isFirstResponder{
                return communication.count
            }else if lfglfmTextField.isFirstResponder{
                return lfglfm.count
            }
            return 0
        }
    
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 1
        }
    
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            if gameTextField.isFirstResponder{
                return games[row]
            }else if consoleTextField.isFirstResponder{
                return console[row]
            }else if skillTextField.isFirstResponder{
                return skill[row]
            }else if communicationTextField.isFirstResponder{
                return communication[row]
            }else if lfglfmTextField.isFirstResponder{
                return lfglfm[row]
            }
            return nil
        }
    
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            if gameTextField.isFirstResponder{
                let itemselected = games[row]
                gameTextField.text = itemselected
            }else if consoleTextField.isFirstResponder{
                let itemselected = console[row]
                consoleTextField.text = itemselected
            }else if skillTextField.isFirstResponder{
                let itemselected = skill[row]
                skillTextField.text = itemselected
            }else if communicationTextField.isFirstResponder{
                let itemselected = communication[row]
                communicationTextField.text = itemselected
            }else if lfglfmTextField.isFirstResponder{
                let itemselected = lfglfm[row]
                lfglfmTextField.text = itemselected
            }
        }
    
    
    
        /*
         // MARK: - Navigation
    
         // In a storyboard-based application, you will often want to do a little preparation before navigation
         override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
         // Get the new view controller using segue.destinationViewController.
         // Pass the selected object to the new view controller.
         }
         */
    
    }
    

    EDITED:

    You don't need the updatePicker method. It does nothing indeed. I've deleted the createPostTapped method for the purpose of this simple example.