iosswiftuibuttonnsattributedstringnsattributedstringkey

Issues with NSAttributedString and Button


I'm trying to update a button title field with an NSAttributedString. So I tried to set the attributed title but it's not working properly. It does not display the correct attributed properties I've put into the NSAttributedString. I've come to the conclusion that either my method for initializing the NSAttributedString is incorrect or the button is overriding the color.

I get the raw value of the string, but not with the attributed properties.

Card Struct

struct Card {
    private var shape : Shape = Shape.none
    private var color : Color = Color.none
    private var number : Number = Number.none
    private var shading : Shading = Shading.none
    //These attributes are not showing up
    private var strokeTextAttributes : [NSAttributedStringKey:Any] = [NSAttributedStringKey:Any]() 
    private var manipulatedValue : String = ""

    init(shape : Shape, color : Color, number : Number, shading : Shading){
        self.shape = shape
        self.color = color
        self.number = number
        self.shading = shading
        //How many multiples of the shape should be on the card
        for _ in 1...number.rawValue{
            manipulatedValue.append(shape.rawValue)
        }
        //0 is the NSStringKey, 1 is the UIColor
        strokeTextAttributes[color.rawValue.0] = color.rawValue.1
    }

    func rawValue() -> NSAttributedString{
        return NSAttributedString(string: manipulatedValue, attributes: strokeTextAttributes)
    }
}

ViewController Class

class ViewController: UIViewController {
    private var game : Set = Set()

    override func viewDidLoad() {
        super.viewDidLoad()

        for index in 0...game.cardsInPlay.count-1{
            cardButtons[index].layer.borderWidth = 3.0
            cardButtons[index].layer.borderColor = UIColor.black.cgColor
            cardButtons[index].layer.cornerRadius = 8.0
            cardButtons[index].setAttributedTitle(game.cardsInPlay[index]!.rawValue(), for: UIControlState.normal)
        }
    }

    @IBOutlet var cardButtons: [UIButton]!
}

I tried hard coding the values into the initializer of the Card struct. But the same instance would recur. The button displays the proper shape of the card and number, but not the correct color. The color will be the default color in the Main.Storyboard inspector. Light blue. The problem is either the dictionary is not working so strokeTextAttributes doesn't contain anything meaningful, or UIButton is doing something goofy.


Solution

  • You are setting NSAttributedStringKey.strokeColor, but you are not setting NSAttributedStringKey.strokeWidth. That's why you don't get the desired result.
    If it's not present, I guess (and it makes total sense) it's the same at setting the .strokeWidth to 0, which is stated by the documentation "doing nothing":

    Specify 0 (the default) for no additional changes

    I got same result by setting it to 0 or not setting it at all.

    Sample test code:

    let str = "Hello !"
    let attributedString = NSMutableAttributedString.init(string: str,
                                                          attributes: [.font: UIFont.systemFont(ofSize: 40),
                                                                       .foregroundColor: UIColor.white])
    
    let label1 = UILabel(frame: CGRect(x: 30, y: 40, width: 200, height: 50))
    label1.backgroundColor = .lightGray
    label1.attributedText = attributedString
    
    let label2 = UILabel(frame: CGRect(x: 30, y: 95, width: 200, height: 50))
    label2.backgroundColor = .lightGray
    label2.attributedText = attributedString
    
    
    let label3 = UILabel(frame: CGRect(x: 30, y: 150, width: 200, height: 50))
    label3.backgroundColor = .lightGray
    label3.attributedText = attributedString
    
    let label4 = UILabel(frame: CGRect(x: 30, y: 205, width: 200, height: 50))
    label4.backgroundColor = .lightGray
    label4.attributedText = attributedString
    
    attributedString.addAttributes([NSAttributedStringKey.strokeColor: UIColor.red],
                                   range: NSRange.init(location: 0, length: attributedString.string.utf16.count))
    label2.attributedText = attributedString
    print("Only Stroke Color:\n\(attributedString)")
    
    attributedString.addAttributes([NSAttributedStringKey.strokeWidth: 0],
                                   range: NSRange.init(location: 0, length: attributedString.string.utf16.count))
    label3.attributedText = attributedString
    print("Stroke Color + Width set to 0:\n\(attributedString)")
    
    attributedString.addAttributes([NSAttributedStringKey.strokeWidth: -4],
                                   range: NSRange.init(location: 0, length: attributedString.string.utf16.count))
    label4.attributedText = attributedString
    print("Stroke Color + Width set to -4:\n\(attributedString)")
    
    self.view.addSubview(label1)
    self.view.addSubview(label2)
    self.view.addSubview(label3)
    self.view.addSubview(label4)
    

    Log output:

    $>Only Stroke Color:
    Hello !{
        NSColor = "UIExtendedGrayColorSpace 1 1";
        NSFont = "<UICTFont: 0x7f8973e11120> font-family: \".SFUIDisplay\"; font-weight: normal; font-style: normal; font-size: 40.00pt";
        NSStrokeColor = "UIExtendedSRGBColorSpace 1 0 0 1";
    }
    $>Stroke Color + Width set to 0:
    Hello !{
        NSColor = "UIExtendedGrayColorSpace 1 1";
        NSFont = "<UICTFont: 0x7f8973e11120> font-family: \".SFUIDisplay\"; font-weight: normal; font-style: normal; font-size: 40.00pt";
        NSStrokeColor = "UIExtendedSRGBColorSpace 1 0 0 1";
        NSStrokeWidth = 0;
    }
    $>Stroke Color + Width set to -4:
    Hello !{
        NSColor = "UIExtendedGrayColorSpace 1 1";
        NSFont = "<UICTFont: 0x7f8973e11120> font-family: \".SFUIDisplay\"; font-weight: normal; font-style: normal; font-size: 40.00pt";
        NSStrokeColor = "UIExtendedSRGBColorSpace 1 0 0 1";
        NSStrokeWidth = "-4";
    }
    

    Rendering:

    enter image description here