Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Formatting alignment of uipickerview

I have searched and cannot find anything that can help me format the alignment of each row in my pickerview.

Currently it looks like this:

PoundsPence_PickerView

What I would like to do is right justify the left £ row and left justify the right pence row so that there is no gap and the current value would be £25.31 instead or the large gap that exists now.

I found some code that formats backgrounds and font size but not alignment.

Any help or links would be appreciated.

This is my full ViewController code...

import Foundation
import UIKit

class LocationViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

    @IBOutlet weak var DisplayStartMileage: UITextField!
    @IBOutlet weak var labelFuelAmount: UILabel!
    @IBOutlet weak var spinFuelAmount: UIPickerView!

    var mileageToPass: String!

    var fuelAmount: Double = 0.00

    var pickerData = [[String]]()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        var poundValues = [String]()
        var penceValues = [String]()
        for var indexP:Int = 0; indexP < 100; indexP += 1 {
            poundValues.append("£ \(indexP)")
            penceValues.append(NSString(format: ".%02d", indexP) as String)
        }

        self.pickerData = [poundValues, penceValues]

        spinFuelAmount.delegate = self
        spinFuelAmount.dataSource = self

    }

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

    @IBAction func FuelSegmentChanged(sender: UISegmentedControl) {

        switch sender.selectedSegmentIndex
        {
        case 0:
            labelFuelAmount.hidden = false
            spinFuelAmount.hidden = false

        case 1:
            labelFuelAmount.hidden = true
            spinFuelAmount.hidden = true

        default:
            break; 
        }

    }

    func numberOfComponentsInPickerView(spinFuelAmount: UIPickerView) -> Int {
        return pickerData.count
    }

    func pickerView(spinFuelAmount: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerData[component].count
    }

    func pickerView(spinFuelAmount: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
        return pickerData[component][row]
    }

    func pickerView(spinFuelAmount: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        var firstComponent = pickerData[0][spinFuelAmount.selectedRowInComponent(0)]
        firstComponent = firstComponent.stringByReplacingOccurrencesOfString( "£ ", withString: "" )

        var secondComponent = pickerData[1][spinFuelAmount.selectedRowInComponent(1)]
        secondComponent = secondComponent.stringByReplacingOccurrencesOfString( ".", withString: "" )

        if let firstValue = firstComponent.toInt(), let secondValue = secondComponent.toInt() {
            let fuelAmount = firstValue + secondValue / 100
        }

    }

    func pickerView(spinFuelAmount: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {

        let titleData = pickerData[row]
        var myString1 = NSMutableAttributedString(string:titleData)
        let myString1Font1 = UIFont(name:"AvenirNext-Regular", size:24.0)
        let myString1Color1 = UIColor(red: 0.292745, green: 0.461693, blue: 0.998524, alpha: 1.000000)
        let originalNSString = myString1.string as NSString
        let myString1Range1 = originalNSString.rangeOfString(titleData)
        var myString1ParaStyle1 = NSMutableParagraphStyle()
        myString1ParaStyle1.baseWritingDirection = NSWritingDirection.Natural
        myString1ParaStyle1.lineBreakMode = NSLineBreakMode.ByWordWrapping
        myString1.addAttribute(NSUnderlineColorAttributeName, value:myString1Color1, range:myString1Range1)
        myString1.addAttribute(NSParagraphStyleAttributeName, value:myString1ParaStyle1, range:myString1Range1)
        myString1.addAttribute(NSFontAttributeName, value:myString1Font1!, range:myString1Range1)

        if component == 0 {
            myString1ParaStyle1.alignment = NSTextAlignment.Left
        } else if component == 1 {
            myString1ParaStyle1.alignment = NSTextAlignment.Right
        }

        return myString1
    }

    func pickerView(spinFuelAmount: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {

        var pickerLabel = view as! UILabel!
        if view == nil {
            pickerLabel = UILabel()
            let hue = CGFloat(row)/CGFloat(pickerData.count)
            pickerLabel.backgroundColor = UIColor(hue: hue, saturation: 1.0, brightness:1.0, alpha: 1.0)
        }
        let titleData = pickerData[row]
        var myString1 = NSMutableAttributedString(string:titleData)
        let myString1Font1 = UIFont(name:"AvenirNext-Regular", size:24.0)
        let myString1Color1 = UIColor(red: 0.292745, green: 0.461693, blue: 0.998524, alpha: 1.000000)
        let originalNSString = myString1.string as NSString
        let myString1Range1 = originalNSString.rangeOfString(titleData)
        var myString1ParaStyle1 = NSMutableParagraphStyle()
        myString1ParaStyle1.baseWritingDirection = NSWritingDirection.Natural
        myString1ParaStyle1.lineBreakMode = NSLineBreakMode.ByWordWrapping
        myString1.addAttribute(NSUnderlineColorAttributeName, value:myString1Color1, range:myString1Range1)
        myString1.addAttribute(NSParagraphStyleAttributeName, value:myString1ParaStyle1, range:myString1Range1)
        myString1.addAttribute(NSFontAttributeName, value:myString1Font1!, range:myString1Range1)
        pickerLabel!.attributedText = myString1

        if component == 0 {
            myString1ParaStyle1.alignment = NSTextAlignment.Left
        } else if component == 1 {
            myString1ParaStyle1.alignment = NSTextAlignment.Right
        }


        return pickerLabel
    }
}
like image 832
Mych Avatar asked Aug 15 '15 15:08

Mych


3 Answers

I used this to right justify text in a pickerview:

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
  var pickerLabel: UILabel? = (view as? UILabel)
  if pickerLabel == nil {
    pickerLabel = UILabel()
    pickerLabel?.font = UIFont.systemFont(ofSize: 20.0)
    pickerLabel?.textAlignment = .right
  }

  pickerLabel?.text = data[row]
  pickerLabel?.textColor = UIColor.red

  return pickerLabel!
}
like image 114
Json Avatar answered Oct 23 '22 01:10

Json


Perhaps a better approach .... The following method could be of help:

// Swift
//   UIPickerView Delegate method

func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
    return CGFloat(50.0)
}

Using this, the "bloat" of code could be removed and the following achieved with 2 components:

centered and tight components

By default the components will center align, and it appears the whole picker will also center align.

like image 35
David Avatar answered Oct 23 '22 01:10

David


For anyone trying to align multiple components like in UIDatePicker, i'm doing this for my Month & Year only picker view:

I have a String extension to calculate the width:

extension String {
func width(withConstraintedHeight height: CGFloat, font: UIFont) -> CGFloat {
    let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
    let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

    return ceil(boundingBox.width)
}
}

Then i use it to calculate the width of the biggest value in each component and set its width in pickerview delegate

func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
    let componentValues = self.pickerViewDataSource[component]
    var maxWidth = CGFloat(0)

    for value in componentValues {
        let valueWidth = value.width(withConstraintedHeight: 20, font: self.pickerLabelFont)
        if valueWidth > maxWidth {
            maxWidth = valueWidth
        }
    }

    return maxWidth + 5
}

and now i create the label using the same font used to calculate the width

func pickerView(_ pickerView: UIPickerView,
                viewForRow row: Int,
                forComponent component: Int,
                reusing view: UIView?) -> UIView
{

    var pickerLabel = view as? UILabel;

    if (pickerLabel == nil)
    {
        pickerLabel = UILabel()

        pickerLabel?.font = self.pickerLabelFont
        pickerLabel?.textAlignment = NSTextAlignment.center
    }

    if component < self.pickerViewDataSource.count && row < self.pickerViewDataSource[component].count {
        pickerLabel?.text = self.pickerViewDataSource[component][row]
    }

    pickerLabel!.adjustsFontSizeToFitWidth = true
    return pickerLabel!;
}

This makes each component in the UIPickerView uses only the width it needs to display the biggest value. By default, UIPickerView will center align the components, so it will stay close each other, that why I've put the +5 for a margin. See below the example of how my picker is now:

my picker view

like image 27
Jean Robert Avatar answered Oct 23 '22 00:10

Jean Robert