1

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.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
nwar1994
  • 53
  • 5
  • UIButton follow **tintColor** property if that button type is **system**. Try to change button type to **custom** ? – Tuesleep Jul 08 '18 at 01:33
  • Hmm... just made it black with no button clicking effect – nwar1994 Jul 08 '18 at 01:42
  • There's a lot of missing info from your question. What are the actual attributes being applied to the attributed string? Add `print("attributes: \(strokeTextAttributes)")` to your `Card.rawValue` function and then update your question with the exact output of a couple of the prints. – rmaddy Jul 08 '18 at 03:35
  • attributes: [__C.NSAttributedStringKey(_rawValue: NSStrokeColor): UIExtendedSRGBColorSpace 1 0 0 1] attributes: [__C.NSAttributedStringKey(_rawValue: NSStrokeColor): UIExtendedSRGBColorSpace 0 0 1 1] – nwar1994 Jul 08 '18 at 05:09
  • I'm pretty sure there's something wrong with my button.setAttributedTitle... I hard coded the attributes using [.strokeColor : UIColor.orange]... Still didn't work. So that must mean something is going on with the button. – nwar1994 Jul 08 '18 at 06:49
  • You set the `strokeColor`, but didn't set the `strokeWidth`. – Larme Jul 08 '18 at 08:18
  • @nwar1994 As I said, update your question. Posting details in comments is the wrong place. Details belong in your question where people will more easily see them. – rmaddy Jul 08 '18 at 16:41

1 Answers1

1

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

Larme
  • 24,190
  • 6
  • 51
  • 81
  • Bro, you are a legend... I've been scratching my head for 2 days lol! Might I ask, how did you figure this out from the logs? – nwar1994 Jul 08 '18 at 14:04
  • I'm familiar with `NSAttributedString`. Some of them needs two settings. When you know how much you can modify the settings, it seems normal to be able to set a width for the stroke, and in your log there wasn't, only color. Also, logic is similar with `myView.layer.borderColor` and `myView.layer.borderWidth`. – Larme Jul 08 '18 at 14:24