I have a picker set up and want to have the user make a selection then tap a button which leads to a url. This is what I have so far:-
class PickerViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var picker: UIPickerView!
#IBOutlet weak var label: UILabel!
var url = NSURL(string: "http://www.google.com")
var pickerData: [String] = [String]()
var pickerSites: [String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.picker.delegate = self
self.picker.delegate = self
pickerData = ["Google", "Facebook"]
pickerSites = ["http://www.google.com", "http://www.facebook.com"]
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
label.text = pickerSites[row]
}
siteBtn.addTarget(self, action: "didTapSite", forControlEvents: .TouchUpInside)
#IBAction func sitesBtn(sender: AnyObject) {
UIApplication.shared().openURL(NSURL(string: "http://www.google.com")!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I've connected the "siteBtn" to a button on the screen. The picker and text label were working fine until I added the code for the button. I'm not sure if I've put the button code in the correct place. I know that I need the button to connect with the picker "didSelectRow" and that the "pickerData" list needs to correlate to the "pickerSites" list but I'm stuck.
Any help would be much appreciated.
this is the minimal setup you need. feel free to ask if anything is unclear:
// outlet to the pickerview
#IBOutlet weak var picker: UIPickerView!
// datasource
let pickerData = ["Google", "Facebook"]
let pickerSites = ["http://www.google.com", "http://www.facebook.com"]
// pickerview datasource methods
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
// pickerview delegate method
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
// ibaction for button tap
#IBAction func goToURLButtonTapped(sender: UIButton) {
let selectedSite = pickerSites[picker.selectedRowInComponent(0)]
UIApplication.sharedApplication().openURL(NSURL(string: selectedSite)!)
}
Related
In my searches, I see this is a common question but I've tried some of the solutions and haven't been able to resolve. A simple example below. When I run the app, and press button, 0 prints as expected. After pressing button2, then button, 1 prints, also as expected. If I move the picker, then press button, I expect 2, but still get 1.
I gather this is because ViewController().sample() is creating a copy, and not actually changing the variable in the "original" ViewController(). I'm stumped at what needs to be reconfigured to get the desired behavior.
import UIKit
class pickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
ViewController().sample()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
var test = Int()
#IBAction func button(_ sender: Any) {
print(test)
}
#IBAction func button2(_ sender: Any) {
test = 1
}
func sample() {
test = 2
}
}
This is a situation where you would either use a delegation pattern or a callback closure; this latter is more "Swifty".
With delegation:
protocol PickerHelperDelegate {
func pickerHelper(_ helper: selectedRow row:)
}
Then in your PickerHelper you add a delegate property and invoke the delegate when required:
class PickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
var delegate: PickerHelperDelegate?
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.delegate?.pickerHelper(self, selectedRow: row)
}
}
In your view controller you need to assign the delegate and implement the protocol function:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
helper1.delegate = self // Assign this object as the picker helper's delegate
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
var test = Int()
}
extension ViewController: PickerHelperDelegate {
func pickerHelper(_ helper: PickerHelper, selectedRow row:Int) {
self.sample()
print("Selected row \(row)")
}
}
You can do a similar thing with a closure:
class PickerHelper: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
let data: [String]
var changeHandler: ((Int)->Void)?
init(data: [String]) {
self.data = data
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.changeHandler?(row)
}
}
In your view controller you need to assign a closure to the changeHandler property:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
helper.changeHandler = { row in
self.sample()
print("Selected row \(row)")
}
}
You could also change your protocol or closure to pass back the data element rather than just the row number and use generics for your PickerHelper so that it wasn't just limited to strings.
Note that classes start with a capital by convention, so you should say PickerHelper, not pickerHelper.
You can use the static property to keep its state in class.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
p1.delegate = helper1
p1.dataSource = helper1
}
#IBOutlet weak var p1: UIPickerView!
let helper1 = pickerHelper(data:["a", "b", "c"])
static var test = Int()
#IBAction func button(_ sender: Any) {
print(test)
}
#IBAction func button2(_ sender: Any) {
ViewController.test = 1
}
static func sample() {
test = 2
}
}
I have been trying to figure out this problem for hours, now I have only one small problem remaining:
I use 2 UI pickers on one view controller, and when I try to select one (aka I'm clicking into the textfield) all I see is question marks, but if I click on one of them, the text will appear in the textfield. I just don't see what am I choosing in the picker.
I already tried using normal pickerviews, I used tags for each pickers, but nothing seemed to work. I know how it should work, I watched a ton of tutorials, but something is still missing. Can you please help me? Thank you!
Here is the code:
import UIKit
class SelectionViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
#IBOutlet weak var ageTextField: UITextField!
#IBOutlet weak var weightTextField: UITextField!
#IBOutlet weak var genderTextField: UITextField!
#IBOutlet weak var lifeStyleTextField: UITextField!
let picker1 = UIPickerView()
let picker2 = UIPickerView()
var genders = ["Male", "Female"]
var lifeStyle = ["Sitting", "Normal", "Active"]
override func viewDidLoad() {
super.viewDidLoad()
picker1.dataSource = self
picker1.delegate = self
picker2.dataSource = self
picker2.delegate = self
genderTextField.inputView = picker1
lifeStyleTextField.inputView = picker2
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponentsInPickerView(pickerView : UIPickerView!) -> Int{
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
if pickerView == picker1 {
return genders.count
} else {
return lifeStyle.count
}
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
if pickerView == picker1 {
return genders[row]
} else if pickerView == picker2{
return lifeStyle[row]
}
else {
print("No pickerview selected.")
}
return ("Pickeview not selected")
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == picker1 {
genderTextField.text = genders[row]
self.view.endEditing(false)
} else if pickerView == picker2{
lifeStyleTextField.text = lifeStyle[row]
self.view.endEditing(false)
}
else {
print("Love love love I want your love")
}
}
}
And here's the thing I see:
You need this signature ( missed _ )
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
and numberOfComponentsInPickerView should return 1
What is wrong with the code that I have produced? I am trying to get a UIPickerView to pop up when the textfield is tapped then go away once a selection is made. The textfield is supposed to present what was selected after.
import UIKit
class CreateAJob_View_ControllerViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
#IBOutlet var pickerTextField: UITextField!
#IBOutlet var picker: UIPickerView!
var pickerData:[String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
picker.hidden = true;
pickerTextField.text = "A4";
self.pickerTextField.delegate = self
self.picker.delegate = self
self.picker.dataSource = self
pickerData = ["A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerTextField.text = pickerData[row];
picker.hidden = true;
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
pickerTextField.hidden = false
return false
}
}
You need to change these two methods this way:
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.pickerTextField.hidden = false;
self.picker.hidden = true;
self.pickerTextField.text = pickerData[row];
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
self.pickerTextField.hidden = true
self.picker.hidden = false;
return false
}
How to navigate between two viewcontrollers using a UIPickerview
I am trying to navigate between two viewcontrollers using a UIPickerview, so i first learned how to use didSelectRow to change the title of a label and then i tried using some code to navigate to another viewcontroller but that didn't work.
The code that i used was:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet var label: UILabel!
#IBOutlet var pickerView: UIPickerView!
var food = ["hello", "hi", "hey"]
var placementAnswer = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
pickerView.delegate = self
pickerView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return food.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return food[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
placementAnswer = row
}
#IBAction func labelChanged(sender: UIButton) {
if (placementAnswer == 0){
}else if (placementAnswer == 1){
let view2 =
self.storyboard?.instantiateViewControllerWithIdentifier("view2") as! ViewController2
self.navigationController?.pushViewController(view2, animated: true)
}else if (placementAnswer == 2){
}
}
}
How can I add other picker view in my view controller
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var UnitTypeLabel: UILabel!
#IBOutlet weak var UnitTypeSelectBTN: UIButton!
#IBOutlet weak var UnitTypePicker: UIPickerView!
let UnitDataArray = ["Unit for Weight","Unit for Length","Unit for Area","Unit for Volume","Unit for Quantity"]
let UnitforLengthData = ["m","km","cm","mm","yd","ft","in"]
let UnitforWeightData = ["g","kg","m.t","l.t","sh.t","lb"]
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return UnitDataArray.count
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return UnitDataArray[row]
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
return UnitTypeLabel.text = UnitDataArray[row]
}
override func viewDidLoad() {
super.viewDidLoad()
//UnitTypePicker.hidden = true
UnitTypePicker.delegate = self
UnitTypePicker.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is how it should be, you have to implement pickerView viewForRow method to achieve this:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var pickerView: UIPickerView!
let UnitDataArray = ["Unit for Weight","Unit for Length","Unit for Area","Unit for Volume","Unit for Quantity"]
override func viewDidLoad() {
super.viewDidLoad()
// pickerView delegate n dataSource
pickerView.dataSource = self
pickerView.delegate = self
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return UnitDataArray.count
}
//MARK: Delegates
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return UnitDataArray[row]
}
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView
{
var pickerLabel = UILabel()
pickerLabel.textColor = UIColor.blackColor()
pickerLabel.text = UnitDataArray[row]
if let pickerViewFont = UIFont(name: "HelveticaNeue-Thin", size: 30) {
pickerLabel.font = pickerViewFont
}
pickerLabel.textAlignment = NSTextAlignment.Center
return pickerLabel
}
func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 40.0
}
}
If you want more number of pickerView then you will have to set those number of components in it like this:
func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int {
return 2 //number of pickerViews
}
By changing the number, you can set those number of pickerView in same viewController.
But if you want to change only dataSet for only one pickerView after any action then you can see this How do I reload/refresh the UIPickerView (with new data array) based on button press?