In my app I have a settings page, and I would like a UIPickerView that works as a check box(lists items and you can enable or disable them). I've looked up different solutions and all I could find was using viewForRow and using UIButton. I am able to add the buttons and it looks good but the buttons don't seem to be tappable.
Heres my implementation:
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView{
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(screenSelectorButtonPress(_:)), for: .touchUpInside)
button.tag = 0
if row == 0{
button.setTitle(Array3[row], for: .normal)
}else{
button.setTitle("\u{2610} \(Array3[row])", for: .normal)
}
return button
}
#objc func screenSelectorButtonPress(_ sender:UIButton!){
print("test")
}
The cells all populate properly but tapping them does nothing.
The functionality that I want is exactly as seen here in safari.
Is there another way to do this or am I doing something wrong with the button? Also yes I could just use switches but our Android version of the app uses a check list like how safari does and we would like to keep it consistent.
You should implement
func pickerView(_ pickerView: UIPickerView,
didSelectRow row: Int,
inComponent component: Int)
//
self.pickerView.delegate = self
//
class ViewController: UIViewController , UIPickerViewDelegate,UIPickerViewDataSource , UIGestureRecognizerDelegate {
let pickerView = UIPickerView()
override func viewDidLoad() {
super.viewDidLoad()
pickerView.frame = CGRect(x: 0, y: 30, width: self.view.frame.width, height: 300)
pickerView.delegate = self
pickerView.dataSource = self
view.addSubview(pickerView)
let tap = UITapGestureRecognizer(target: self, action: #selector(pickerTapped))
tap.delegate = self
pickerView.addGestureRecognizer(tap)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return Array3.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(row)
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if row == 0 {
return Array3[row]
}
else {
return "\u{2610} \(Array3[row])"
}
}
#objc func pickerTapped(tapRecognizer: UITapGestureRecognizer) {
if tapRecognizer.state == .ended {
let rowHeight = self.pickerView.rowSize(forComponent: 0).height
let selectedRowFrame = self.pickerView.bounds.insetBy(dx: 0, dy: (self.pickerView.frame.height - rowHeight) / 2)
let userTappedOnSelectedRow = selectedRowFrame.contains(tapRecognizer.location(in: self.pickerView))
if userTappedOnSelectedRow {
let selectedRow = self.pickerView.selectedRow(inComponent: 0)
pickerView(self.pickerView, didSelectRow: selectedRow, inComponent: 0)
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
Related
should look like this
In pickerView i want to change title font size, as I scroll the selected row title font will be of high font size and above selected title font size will be decreasing and same for below selected row.
import UIKit
Vc:
class ViewController: UIViewController {
#IBOutlet weak var pickerView: UIPickerView!
var pickerTitle = ["10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00","10:00"]. // time to display in pickerView
var fontSize = [4,6,8,10,12,14,16,18,20,22,24,26,24,22,20,18,16,14,12,10,8,6,4,2] // font size when view is loaded and when I scroll I need to change the font size so this won't work I guess
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pickerView.delegate = self
pickerView.dataSource = self
pickerView.reloadAllComponents()
pickerView.selectRow(11, inComponent: 0, animated: true)
}
}
datasource and delete for pickerView:
extension ViewController: UIPickerViewDelegate,UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerTitle.count
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
let titleData = pickerTitle[row]
let myTitle = NSAttributedString(string: titleData, attributes: [NSAttributedString.Key.font:UIFont(name: "Georgia", size: CGFloat(fontSize[row]))!,NSAttributedString.Key.foregroundColor:UIColor.black])
pickerLabel.attributedText = myTitle
pickerLabel.textAlignment = .right
return pickerLabel
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
for var i in 0...row{
print(i)
}
for var i in row..<pickerTitle.count{
print(i)
}
pickerView.reloadAllComponents()
}
}
Not sure what your requirements are, and what you're doing in the code.
But what I could understand is that you want an increased font size for selected title in pickerView, and the rest unselected titles stays smaller; then here is the code:
(if not, please clarify further)
extension ViewController: UIPickerViewDelegate,UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerTitle.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
pickerView.reloadAllComponents()
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var label = view as! UILabel?
if label == nil {
label = UILabel()
label?.textAlignment = .center
}
switch component {
case 0:
label?.text = pickerTitle[row]
if(pickerView.selectedRow(inComponent: 0) == row){
label?.font = UIFont(name: "Georgia", size: 26)
}
return label!
default:
return label!
}
}
}
MY Scenario, I am trying to create button click to open UIPickerView and selecte picker data to show on button title using swift. Here, Toolbar also I would like to add into the pickerview controller.
let button = UIButton(type: .custom)
button.setTitle("",for: .normal)
button.frame = CGRect(x: CGFloat(amount_textfield.frame.size.width - 9), y: CGFloat(5), width: CGFloat(9), height: CGFloat(20))
button.addTarget(self, action: #selector(self.refresh), for: .touchUpInside)
amount_textfield.leftView = button
amount_textfield.leftViewMode = .always
#IBAction func refresh(_ sender: Any) {
// Here, I need to execute picker view
}
There are few steps that you have to follow:
Create initially hidden UIPickerView and set its delegate and dataSource
#IBOutlet weak var pickerView: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
}
Have data source array which you use for this picker view
class ViewController: UIViewController {
var array = [String]()
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return array.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return array[row]
}
}
Unhide your picker view when button is pressed
pickerView.isHidden = false
Integrate picker view's delegate method pickerView(_:didSelectRow:inComponent:). When row is selected, set title of button as element from your data source array at index as selected row
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
button.setTitle(array[row], for: .normal)
}
Optional: Hide picker view
pickerView.isHidden = true
It seems that I cannot select the very first row in the UIPickerView when I first load it. I want the textfield to update immediately when I load the picker view. It only updates when I select something else, and then go back to the first row.
var platformData = ["XBOX", "PS4", "PC"]
var picker = UIPickerView()
#IBOutlet var platformSelected: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
picker.dataSource = self
platformSelected.inputView = picker
let toolbar = UIToolbar()
toolbar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneAction))
toolbar.items = [doneButton]
platformSelected.inputAccessoryView = toolbar
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return platformData.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
platformSelected.text = platformData[row]
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return platformData[row]
}
Improve your code.
platformSelected.delegate = self
......
// MARK: - UITextFieldDelegate
extension YourUIViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
// TODO: - Specify index what you need. After editing it changed and you should get selected index using its position in platformData Array
let index = 0
picker.selectRow(index, inComponent: 0, animated: true)
}
}
I am trying to have multiple picker views in one single view in swift.
So far I have created 2 different textfields and I want both of them to have different picker views if I click on them. so let us say if click on textfield #1 it opens the array #1 and textfields #2 the second.
I have already looked up these questions but they do not really answer my question or solve my problem:
Multiple Picker Views on a single view
Creating Multiple Dynamic Picker Views
so my View Controller looks like this:
how my viewController should look
and this is my piece of code:
let pickOption = ["kg","lb"] //first array for first textfield
let ageOption = ["0-5", "6-10", "11-15"] //array for 2nd textfield
let pickerView = UIPickerView()
//picker View functions
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickOption.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickOption[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
weightTextField.text = pickOption[row]
}
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
weightTextField.inputView = pickerView
weightTextField.text = pickOption[0]
}
so as mentioned before, the first textfield opens up the array 'pickOption' and the second array opens up 'ageOption'
EDIT: 'weightTextField' ist the first textfield which opens up the first array(pickOption)
We can do it for multiple UITextField from single PickerView, with the help of UITextFieldDelegate
let pickOption = ["kg","lb"] //first array for first textfield
let ageOption = ["0-5", "6-10", "11-15"] //array for 2nd textfield
let pickerView = UIPickerView()
var currentTxtFldTag : Int = 10
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
weightTextField.tag = 10
ageTextField.tag = 20
weightTextField.delegate = self
ageTextField.delegate = self
weightTextField.inputView = pickerView
weightTextField.text = pickOption[0]
ageTextField.inputView = pickerView
ageTextField.text = ageOption[0]
// Do any additional setup after loading the view.
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if currentTxtFldTag == 10
{
return pickOption.count
}
else
{
return ageOption.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if currentTxtFldTag == 10
{
return pickOption[row]
}
else
{
return ageOption[row]
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if currentTxtFldTag == 10
{
weightTextField.text = pickOption[row]
}
else
{
ageTextField.text = ageOption[row]
}
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField.tag == 10 // WEIGHT OPTION
{
currentTxtFldTag = 10
}
else // AGE OPTION
{
currentTxtFldTag = 20
}
pickerView.reloadAllComponents()
return true
}
Output
Suppose that you have two pickerView controls: picker0 and picker1.
class HomeViewController: BasicViewController, UITextFieldDelegate, UITextViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource {
let numberArray = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180]
var areaArray = [String]()
#IBOutlet weak var picker0: UIPickerView!
#IBOutlet weak var picker1: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
// area //
for i in 0..<11 {
let str = "Area "
let localStr = NSLocalizedString(str + String(i), comment: "")
areaArray.append(localStr)
}
}
// MARK: - Campaign duration & area
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == picker0 {
return numberArray.count
} else {
return areaArray.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == picker0 {
return String(numberArray[row]) + " pieces"
} else {
return areaArray[row]
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == seventhPicker {
} else {
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
weightTextField.inputView = pickerView
}
let pickOption = ["kg","lb"] //first array for first textfield
let ageOption = ["0-5", "6-10", "11-15"] //array for 2nd textfield
let pickerView = UIPickerView()
//picker View functions
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if weightTextField1.tag == 1 {
return pickOption.count
} else if weightTextField2.tag == itemPicker {
return ageOption.count
}
return 0
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if weightTextField1.tag == 1 {
return pickOption[row]
} else if weightTextField2.tag == 1 {
return ageOption[row]
}
return 0
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if weightTextField1.tag == 1 {
weightTextField1.text = pickOption[row]
} else if weightTextField2.tag == 1 {
weightTextField2.text = ageOption[row]
}
}
////set delegate
func textFieldDidBeginEditing(textField: UITextField!) { //delegate method
if textField == weightTextField1
{
weightTextField1.atg = 1;
weightTextField2.atg = 0;
}
else if textField == weightTextField2
{
weightTextField1.atg = 0;
weightTextField2.atg = 1;
}
picker.reloadAllComponents()
}
}
is it possible to create UIPickerView where there will be text and image in one row?
I know how to create it with text only:
class FirstViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
var currArray = ["USD","GBP"]
var flags = ["USD.jpg", "GBP.jpg"]
var picker = UIPickerView()
#IBOutlet weak var currencySelectorLabel: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
picker.dataSource = self
currencySelectorLabel.inputView = picker
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
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 currArray.count
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
currencySelectorLabel.text = currArray[row]
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return currArray[row]
}
}
But I would like to have something like this:
Obviously instead of image files' names should be real images.
And I want to assign label text from UIPickerView as it is right now.
With help of this post How can I get images to appear in UI PickerView Component in Swift? everything seems to work!
Try this to implement title and image in PickerView
#IBOutlet weak var pickerView: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
picker.delegate = self
picker.dataSource = self
currencySelectorLabel.inputView = picker
}
// MARK: UIPickerViewDataSource
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return currArray.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return currArray[row] as? String
}
// MARK: UIPickerViewDelegate
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
let myView = UIView(frame: CGRect(x: 0, y: 0, width: pickerView.bounds.width - 50, height: 40))
let myImageView = UIImageView(frame: CGRect(x: 60, y: 0, width: 30, height: 30))
let countryLabel = UILabel(frame: CGRect(x: 110, y: 0, width: pickerView.bounds.width - 90, height: 40 ))
myImageView.image = flags[row]
countryLabel.font = UIFont.boldSystemFont(ofSize: 16.0)
countryLabel.textColor = UIColor.white
countryLabel.text = currArray[row] as? String
myView.addSubview(countryLabel)
myView.addSubview(myImageView)
return myView
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// do something with selected row
}