Search code examples
swiftuipickerview

Change UIBackground with Picker View in Swift


Im trying to change the UIBackground with colors provided in a picker. I have the picker working fine and can print the selected color, however my problem is getting the selectedColor to change the UIBackground with the push of the selectedColorButton. I thought I could pass in the selectedColor at the end of view.backgroundColor = UIColor., but I can't get it to work and I guess going about it incorrectly.

Thanks!

import UIKit

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{
    
    let colors = ["Red", "Green", "Orange", "Yellow", "Pink", "Purple"]
    
    var selectedColor = ""

    
    @IBAction func selectedColorButton(_ sender: UIButton) {
        
    //    view.backgroundColor = UIColor.

    }
    
    @IBOutlet weak var pickerView: UIPickerView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pickerView.delegate = self
        pickerView.dataSource = self
        
}
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return colors.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return colors[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        return selectedColor = colors[row]

    }


}

Solution

  • As you've discovered view.backgroundColor expects a value of type UIColor and unfortunately all you have available is a String. There's no direct conversion but there are two approaches you can take here:

    1. Run a second array that contains UIColor values

    You're presenting your picker options using a colors array here:

    let colors = ["Red", "Green", "Orange", "Yellow", "Pink", "Purple"]
    

    You can replace that implementation with a second array that contains the actual UIColor values in the same order. Now, instead of tracking the selected name, track the selected index

    var selectedIndex = 0
    let colorNames = ["Red", "Green", "Orange", "Yellow", "Pink", "Purple"]
    let colors: [UIColor] = [.red, .green, .orange, .yellow, .pink, .purple]
    

    Present your options using colorNames, then use the index to access colors

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
       selectedIndex = row
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return colorNames[row]
    }
    
    @IBAction func selectedColorButton(_ sender: UIButton) {
        view.backgroundColor = colors[selectedIndex]
    }
    
    1. Use a system property for the names

    Instead of having a separate array just to store the names, we can use the accessibility names of the colors. Now, all we need is a colors array and we can directly store the selected color, no index tracking or name selection

    var selectedColor: UIColor? = nil
    let colors: [UIColor] = [.red, .green, .orange, .yellow, .pink, .purple]
    

    Now present those color options and use their accessibilityName properties for the names

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        selectedColor = colors[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return colors[row].accessibilityName
    }
    
    @IBAction func selectedColorButton(_ sender: UIButton) {
        if let color = selectedColor {
            view.backgroundColor = color
        }
    }
    

    The advantage of the first approach is that we get to control the names. The advantage of the second approach is that we save the memory for the extra information. Your choice!

    You can even try other approaches, like using an enum or a tuple or even your own classes. I suggest you try them all!