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

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.

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.

you can assign your selected value to particular text field by using textField delegate methods which is textFieldDidBeginediting which is called when textField did started begin editing
like
take one variable
var textFieldSelected = UITextField()
and then in
func textFieldDidBeginEditing(_ textField: UITextField) {
textFieldSelected = textField
}
by doing this you will get you selected textField
and when you done choosing from picker
func doneSelection(){
if textFieldSelected == yourTextField(in which you want to enter your data)
{
yourTextField.text = data you want to enter from picker
}
}

Related

UITextfield as float passed through segue to an UILabel

Im fairly new to swift and would like for a user to enter a number using the decimal pad for UITextfield to enter a float then pass that float to another view controller using a UILabel. Everything works except passing the float to the UILabel on the other view controller. I get this error
"Cannot assign value of type 'UITextField?' to type 'UILabel?'"
import UIKit
class SelectAttributesViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
#IBOutlet weak var kitPickerView: UIPickerView!
#IBOutlet weak var reactionVolumeLabel: UILabel!
#IBOutlet weak var numberOfSampleTextField: UITextField!
#IBOutlet weak var volumeOfTemplateDNATextField: UITextField!
#IBOutlet weak var slider: UISlider!
#IBOutlet weak var calculateButton: UIButton!
let kits = ["kit 1", "Kit 2"]
let pArray = [10,20,50]
override func viewDidLoad() {
super.viewDidLoad()
self.numberOfSampleTextField.delegate = self
self.volumeOfTemplateDNATextField.delegate = self
kitPickerView.dataSource = self
kitPickerView.delegate = self
let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))
view.addGestureRecognizer(tap)
}
func pSliderInterval() {
slider.minimumValue = 0
slider.maximumValue = Float(pArray.count)
slider.isContinuous = false
}
#IBAction func reactionVolumeSlider(_ sender: UISlider) {
print(Int(sender.value))
let currentValue = pArray[Int(sender.value)]
reactionVolumeLabel.text = "\(currentValue) "
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return kits.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if row == 0{ print(kits[row])
}else if row == 1{
createAlert(title: "Kit not available", message: "More kits will be added soon!")
calculateButton.isEnabled = false
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return kits[row]
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let oldText = textField.text, let r = Range(range, in: oldText) else {
return true
}
let newText = oldText.replacingCharacters(in: r, with: string)
let isNumeric = newText.isEmpty || (Double(newText) != nil)
let numberOfDots = newText.components(separatedBy: ".").count - 1
let numberOfDecimalDigits: Int
if let dotIndex = newText.firstIndex(of: ".") {
numberOfDecimalDigits = newText.distance(from: dotIndex, to: newText.endIndex) - 1
} else {
numberOfDecimalDigits = 0
}
return isNumeric && numberOfDots <= 1 && numberOfDecimalDigits <= 2
}
func createAlert (title: String, message: String){
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: { (Action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
// This is the Segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var masterMix = segue.destination as! MasterMixTableViewController
masterMix.waterVolumeLabel = numberOfSampleTextField
}
#IBAction func calculatePressed(_ sender: Any) {
if numberOfSampleTextField.text != ""{
performSegue(withIdentifier: "masterMixSegue", sender: self)
}
}
}
I have browsed heavily for the solution but haven't found anything.
You need
let masterMix = segue.destination as! MasterMixTableViewController
masterMix.loadViewIfNeeded()
masterMix.waterVolumeLabel!.text = numberOfSampleTextField!.text
The error says you are assigning UITextField to UILabel. But you must assign textFeild.text to label.text.
let textField = UITextField()
let label = UILabel()
label.text = textField.text

pickerView didSelectRow is inputting into the wrong UITextField

I am trying to follow the following solution to having multiple UIPickerViews on the one UIViewController. They suggest that a tag for each of the UITextfield which I have done and able to implement the number of rows, title for row and number of components. However, I have reached a stumbling block when implementing the did select row. When I select the UITextField it highlights another UITextfield. Below is the code I have so far.
class DriverViewController: UIViewController {
var selectedTrack: String?
var firstDriver: String?
var secondDriver: String?
var thirdDriver: String?
let tracks = ["Melbourne", "Manama", "Shanghai", "Baku",
"Barcelona", "Monaco", "Montreal","Le Castellet","Spielberg",
"Silverstone","Hockenheim","Budapest","Francorchamps","Monza","Singapore","Sochi","Suzuka","Austin","Interlagos","Abu Dhabi"]
let drivers = ["Lewis Hamilton","Antonio Giovinazzi","Kimi Raikkonen","Charles Leclerc","Sebastian Vettel","Romain Grosjean","Kevin Magnussen","Lando Norris",
"Carlos Sainz","Valtteri Bottas","Sergio Perez","Lance Stroll","Pierre Gasly","Max Verstappen","Nico Hulkenberg","Daniel Ricciardo","Alexander Albon","Daniil Kvyat","Robert Kubica","George Russell"]
#IBOutlet weak var TrackTextField: UITextField!
#IBOutlet weak var firstTextField: UITextField!
#IBOutlet weak var secondTextField: UITextField!
#IBOutlet weak var thirdTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
createTrackPicker()
createDriverPicker()
createToolBar()
// Do any additional setup after loading the view.
}
func createTrackPicker() {
let trackPicker = UIPickerView()
trackPicker.tag = 0
trackPicker.delegate = self
TrackTextField.inputView = trackPicker
}
func createDriverPicker() {
let driverPicker = UIPickerView()
driverPicker.tag = 1
driverPicker.tag = 2
driverPicker.tag = 3
driverPicker.delegate = self
firstTextField.inputView = driverPicker
secondTextField.inputView = driverPicker
thirdTextField.inputView = driverPicker
}
func createToolBar() {
let toolBar = UIToolbar()
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ViewController.dismissKeyboard))
toolBar.setItems([doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
TrackTextField.inputAccessoryView = toolBar
firstTextField.inputAccessoryView = toolBar
secondTextField.inputAccessoryView = toolBar
thirdTextField.inputAccessoryView = toolBar
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
/*
// 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.destination.
// Pass the selected object to the new view controller.
}
*/
}
extension DriverViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView.tag == 0 {
return tracks.count
} else {
return drivers.count
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView.tag == 0 {
return "\(tracks[row])"
} else {
return "\(drivers[row])"
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 0 {
selectedTrack = tracks[row]
TrackTextField.text = selectedTrack
} else if pickerView.tag == 1 {
firstDriver = drivers[row]
firstTextField.text = firstDriver
} else if pickerView.tag == 2 {
secondDriver = drivers[row]
secondTextField.text = secondDriver
} else if pickerView.tag == 3 {
thirdDriver = drivers[row]
thirdTextField.text = thirdDriver
}
}
}
This is how it looks on the screen.
Look at your function:
func createDriverPicker() {
let driverPicker = UIPickerView()
driverPicker.tag = 1
driverPicker.tag = 2
driverPicker.tag = 3
driverPicker.delegate = self
firstTextField.inputView = driverPicker
secondTextField.inputView = driverPicker
thirdTextField.inputView = driverPicker
}
Think about what value the tag property has after this code is run keeping in mind that it can only have one value.
You either need to update the picker view's tag property each time a text field begins editing, or you should abandon the use of the tag and simply check which text field is currently the first responder. See UIPickerView for each text field with different arrays (Swift/Firebase) for an example of how this is done.

Using same pickerView for two buttons returning empty data

Here's my code . I am trying to use UIPickerview for few buttons with different data. but it show's me blank gray picker view when I run my project. some told me that I have to reload the pickerView but I used it for example "mainPV.delegate = self ..... Please I need help guys if someone can help me
import UIKit
class SearchBuyVC: UIViewController {
#IBOutlet weak var optionV: UIView!
#IBOutlet weak var doneBtn: UIButton!
#IBOutlet weak var searchBtn: UIButton!
// picker view
#IBOutlet var mainPV: UIPickerView! // main
#IBOutlet var secPV: UIPickerView! //type
#IBOutlet var minPV: UIPickerView! //priceMin
#IBOutlet weak var typeBtn: UIButton!
#IBOutlet weak var PriceMinBtn: UIButton!
var optionSelector = 0
let searchData = ["Search by Areas", "Search by Map", "Search by LRT/MRTs", "Search by Schools", "Search by Propery Name"]
let typeData = ["All Residental", "All Commerical"]
let minNum = ["Any", "100 k", "200 k", "300 k", "400 k", "500 k", "600k ", "700 k"]
override func viewDidLoad() {
super.viewDidLoad()
setUpNav(arrowType: 2)
mainPV = UIPickerView()
secPV = UIPickerView()
minPV = UIPickerView()
mainPV.delegate = self
secPV.delegate = self
minPV.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//Dispose of any resources that
}
override func viewDidAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
#IBAction func selectOptionsPressed(_ sender: Any) {
openOptions()
mainPV.delegate = self
secPV.delegate = self
minPV.delegate = self
}
#IBAction func typeSelect(_ sender: Any) {
openOptions()
mainPV.delegate = self
secPV.delegate = self
minPV.delegate = self
}
#IBAction func minPriceBtn(_ sender: Any) {
openOptions()
mainPV.delegate = self
secPV.delegate = self
minPV.delegate = self
}
#IBAction func donePressed(_ sender: Any) {
switch optionSelector {
case 0:
FiltersController.instance.showAreaFilter(nc: self.navigationController!)
case 1:
FiltersController.instance.showMapFilter(nc: self.navigationController!)
case 2:
FiltersController.instance.showTrainStations(nc: self.navigationController!)
case 3:
FiltersController.instance.showSchoolFilter(nc: self.navigationController!)
default:
FiltersController.instance.showNameFilter(nc: self.navigationController!)
}
closeOptions()
}
func openOptions() {
optionV.isHidden = false
mainPV.isHidden = false
minPV.isHidden = false
doneBtn.isHidden = false
secPV.isHidden = false
}
func closeOptions(){
optionV.isHidden = true
mainPV.isHidden = true
minPV.isHidden = true
doneBtn.isHidden = true
secPV.isHidden = true
}
#IBAction func nextPressed(_ sender: Any) {
ListingController.instance.showBuyListing(nc: self.navigationController!)
}
}
extension SearchBuyVC: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == mainPV {
return searchData.count
}
return 1
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == mainPV{
return searchData[row]
}
if pickerView == secPV{
return typeData[row]
}
if pickerView == minPV{
return minNum[row]
}
return ""
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
optionSelector = row
if pickerView == mainPV{
searchBtn.setTitle(searchData[row], for: .normal)
}
if pickerView == secPV{
typeBtn.setTitle(typeData[row], for: .normal)
}
if pickerView == minPV{
PriceMinBtn.setTitle(minNum[row], for: .normal)
}
}
}
Also need to set dataSource for the pickerViews. So that the methods of UIPickerViewDataSource called which are responsible for returning all the data to UIPickerView. Your class must to confirm the UIPickerViewDataSource protocol.
Ex:
picker_country.dataSource = self
At first import the UIPickerView protocols within the class as,
class SearchBuyVC: UIViewController UIPickerViewDelegate, UIPickerViewDataSource
and add the following lines also to call the datasource functions,
mainPV.delegate = self
secPV.delegate = self
minPV.delegate = self
mainPV.dataSource = self
secPV.dataSource = self
minPV.dataSource = self

How to hide UIPIckerView when the user touches the row already selected

I have in my code more than one UIPickerView, and let's say that the user opens the PickerView unintentionally, but wants to keep the same row selected, as I do for when the user touches the already selected row, the selector hide?
I tried this: UIPicker detect tap / touch on currently selected row, but I could not make it work.
--- edit ---
I'll try to be more specific. I'm a beginner in programming and the Swift language.
This is my ViewController.swift
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var colorLabel: UILabel!
#IBOutlet weak var sizeLabel: UILabel!
#IBOutlet weak var colorButton: UIButton!
#IBOutlet weak var sizeButton: UIButton!
#IBOutlet weak var resultButton: UIButton!
#IBOutlet weak var colorPickerView: UIPickerView! = UIPickerView()
#IBOutlet weak var sizePickerView: UIPickerView! = UIPickerView()
var colorPickerData = ["Blue", "Red"]
var sizePickerData = ["Small", "Big"]
var descri = String()
var resultadoImagem = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
colorPickerView.isHidden = true
sizePickerView.isHidden = true
self.colorPickerView.delegate = self
self.colorPickerView.dataSource = self
self.sizePickerView.delegate = self
self.sizePickerView.dataSource = self
colorLabel.text = colorPickerData[0]
sizeLabel.text = sizePickerData[0]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView.tag == 1 {
return colorPickerData.count
} else if pickerView.tag == 2 {
return sizePickerData.count
}
return 0
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView.tag == 1 {
return "\(colorPickerData[row])"
} else if pickerView.tag == 2 {
return "\(sizePickerData[row])"
}
return ""
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 1 {
colorLabel.text = colorPickerData[row]
colorPickerView.isHidden = true
} else if pickerView.tag == 2 {
sizeLabel.text = sizePickerData[row]
sizePickerView.isHidden = true
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
colorPickerView.isHidden = true
sizePickerView.isHidden = true
}
#IBAction func colorButton(_ sender: Any) {
colorPickerView.isHidden = !colorPickerView.isHidden
}
#IBAction func sizeButton(_ sender: Any) {
sizePickerView.isHidden = !sizePickerView.isHidden
}
#IBAction func resultButton(_ sender: Any) {
if (colorLabel.text == "Blue")
&& (sizeLabel.text == "Big") { resultadoImagem = UIImage(named: "blue-big.png")!; descri = "BLUE"}
else if (colorLabel.text == "Blue")
&& (sizeLabel.text == "Small") { resultadoImagem = UIImage(named: "blue-small.png)!; descri = "BLUE"}
else if (colorLabel.text == "Red")
&& (sizeLabel.text == "Big") { resultadoImagem = UIImage(named: "red-big.png")!; descri = "RED"}
else if (colorLabel.text == "Red")
&& (sizeLabel.text == "Small") { resultadoImagem = UIImage(named: "red-small.png")!; descri = "RED"}
self.performSegue(withIdentifier: "resultSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "resultSegue" {
let DestViewController : SecondViewController = segue.destination as! SecondViewController
DestViewController.descText = descri
DestViewController.resultPhoto = resultadoImagem
}
}
}
This code works great, when I hit the "Result" button it goes to the SecondViewController and shows photo and description.
My difficulty is, the colorPickerView opens with the data "Blue" selected, just as the sizerPickerView opens with the data "Small" by default. I want pickerView to close/hide when the user touches the data that is already selected.
Conform class to UIGestureRecognizerDelegate protocol
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UIGestureRecognizerDelegate {
// ...
}
Add a UITapGestureRecognizer to your colorPickerView
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapAction(_:)))
tap.cancelsTouchesInView = false
tap.delegate = self
colorPickerView.addGestureRecognizer(tap)
Implement UIGestureRecognizerDelegate method
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
Finally implement tapAction
func tapAction(_ tapRecognizer:UITapGestureRecognizer) {
if tapRecognizer.state == .ended {
let rowHeight : CGFloat = colorPickerView.rowSize(forComponent: 0).height
let selectedRowFrame: CGRect = colorPickerView.bounds.insetBy(dx: 0.0, dy: (colorPickerView.frame.height - rowHeight) / 2.0)
let userTappedOnSelectedRow = selectedRowFrame.contains(tapRecognizer.location(in: colorPickerView))
if (userTappedOnSelectedRow){
let selectedRow = colorPickerView.selectedRow(inComponent: 0)
//do whatever you want here
}
}
}
Replicate steps 2 and 4 using sizerPickerView to extend functionality.

Save uipickerview color in core data

I know what I want, but I'm just struggling to get it the right way. I'm trying to implement a small app, which let the user add a category by providing a category name, description and then select colour from the uipickerview. I've successfully saved the name, description in the core data. I'm just struggling in how to get the selected colour string and save it in the core data. Any help will be appreciated. This is what I've so far as code:
import UIKit
import CoreData
class NewCategory: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
let categoryColor = ["Red","Yellow","Black","White", "Green", "Blue"]
// MARK: - Properties
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
// MARK: Outlets
#IBOutlet weak var name: UITextField!
#IBOutlet weak var descriptionField: UITextView!
#IBOutlet weak var pickerView: UIPickerView!
#IBOutlet weak var colorLabel: UILabel!
// MARK: Actions
#IBAction func saveBtn(sender: AnyObject) {
if name.text == "" || name.text.isEmpty || name.text.isEmpty{
var alert = UIAlertController(title: "WARNING !!!", message: "Couldn't add category. Fill all fields.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
createCategory() }
}
// MARK: View settings
override func viewDidLoad() {
super.viewDidLoad()
self.pickerView.dataSource = self
self.pickerView.delegate = self
}
// Custom functions
func createCategory() {
let entity = NSEntityDescription.entityForName("Category", inManagedObjectContext: context!)
let category = Category(entity: entity!, insertIntoManagedObjectContext: context)
category.name = name.text
category.descript = descriptionField.text
category.color = colorLabel
println(category.name)
context?.save(nil)
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return categoryColor.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return categoryColor[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if (row == 0) {
colorLabel.backgroundColor = UIColor.redColor()
}
else if(row == 1) {
colorLabel.backgroundColor = UIColor.yellowColor()
}
else if(row == 2) {
colorLabel.backgroundColor = UIColor.blackColor()
}
else if(row == 3) {
colorLabel.backgroundColor = UIColor.whiteColor()
}
else if(row == 4) {
colorLabel.backgroundColor = UIColor.greenColor()
}
else {
colorLabel.backgroundColor = UIColor.blueColor()
}
}
}
You can get the color name this way:
let index = pickerView.selectedRowInComponent(0)
let color = categoryColor[index]
For example, you could use it in your function like this:
func createCategory() {
let entity = NSEntityDescription.entityForName("Category", inManagedObjectContext: context!)
let category = Category(entity: entity!, insertIntoManagedObjectContext: context)
category.name = name.text
category.descript = descriptionField.text
let index = pickerView.selectedRowInComponent(0)
let color = categoryColor[index]
category.color = color // (assuming color is a String)
println(category.name)
context?.save(nil)
}
In didSelectRow get the value from categoryColor
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let colorString = categoryColor[row] as! String
// Save the colorString into Core data
}

Resources