Swift 4 Label attributes

2020-02-26 07:16发布

问题:

I'm moving from swift 3 to swift 4. I have UILabels that I am giving very specific text properties to the label. I'm getting an 'unexpectedly found nil while unwrapping optional value' error when strokeTextAttributes is being initialized. I'm totally lost to be frank.

In swift 3 the of strokeTextAttributes was [String : Any] but swift 4 threw errors until I changed it to what it is below.

let strokeTextAttributes = [
    NSAttributedStringKey.strokeColor.rawValue : UIColor.black,
    NSAttributedStringKey.foregroundColor : UIColor.white,
    NSAttributedStringKey.strokeWidth : -2.0,
    NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
    ] as! [NSAttributedStringKey : Any]


chevronRightLabel.attributedText = NSMutableAttributedString(string: "0", attributes: strokeTextAttributes)

回答1:

@Larme's comment about the .rawValue not being needed is correct.

Also, you can avoid the force cast that crashes your code using explicit typing:

let strokeTextAttributes: [NSAttributedString.Key: Any] = [
    .strokeColor : UIColor.black,
    .foregroundColor : UIColor.white,
    .strokeWidth : -2.0,
    .font : UIFont.boldSystemFont(ofSize: 18)
]

This gets rid of the repetitive NSAttributedString.Key., too.



回答2:

In Swift 4.0+, attributed string accepts json (dictionary) with key type NSAttributedStringKey or NSAttributedString.Key.

So you must change it from [String : Any] to

Swift 4.1 & below - [NSAttributedStringKey : Any] &
Swift 4.2 & above - [NSAttributedString.Key : Any]

Swift 4.2

Initialiser for AttributedString in Swift 4.2 is changed to [NSAttributedString.Key : Any]?

public init(string str: String, attributes attrs: [NSAttributedString.Key : Any]? = nil)

Here is sample working code.

let label = UILabel()
let labelText = "String Text"

let strokeTextAttributes = [
     NSAttributedString.Key.strokeColor : UIColor.black,
     NSAttributedString.Key.foregroundColor : UIColor.white,
     NSAttributedString.Key.strokeWidth : -2.0,
     NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 18)
   ] as [NSAttributedString.Key : Any]

label.attributedText = NSAttributedString(string: labelText, attributes: strokeTextAttributes)

Swift 4.0

Initialiser for AttributedString in Swift 4.0 is changed to [NSAttributedStringKey : Any]?.

public init(string str: String, attributes attrs: [NSAttributedStringKey : Any]? = nil)

Here is sample working code.

let label = UILabel()
let labelText = "String Text"

let strokeTextAttributes = [
     NSAttributedStringKey.strokeColor : UIColor.black,
     NSAttributedStringKey.foregroundColor : UIColor.white,
     NSAttributedStringKey.strokeWidth : -2.0,
     NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
   ] as [NSAttributedStringKey : Any]

label.attributedText = NSAttributedString(string: labelText, attributes: strokeTextAttributes)

Look at this Apple Document, for more info: NSAttributedString - Creating an NSAttributedString Object



回答3:

NSAttributedStringKey.strokeColor.rawValue is of type String

NSAttributedStringKey.strokeColor is of type NSAttributedStringKey

So its unable to convert String to NSAttributedStringKey. You have to use like below:

let strokeTextAttributes: [NSAttributedStringKey : Any] = [
    NSAttributedStringKey.strokeColor : UIColor.black,
    NSAttributedStringKey.foregroundColor : UIColor.white,
    NSAttributedStringKey.strokeWidth : -2.0,
    NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
]


回答4:

Swift 4 Attributed text with multiple colors

extension NSMutableAttributedString 
{
@discardableResult func DustyOrange(_ text: String, Fontsize : CGFloat) -> NSMutableAttributedString 
{
    let attrs: [NSAttributedStringKey: Any] = [.font: UIFont(name: "SFUIDisplay-Regular", size: Fontsize)!, NSAttributedStringKey.foregroundColor: UIColor(red: 242.0/255.0, green: 97.0/255.0, blue: 0.0/255.0, alpha: 1.0) ]
    let boldString = NSMutableAttributedString(string:text, attributes: attrs)
    append(boldString)
    return self
}
@discardableResult func WarmGrey(_ text: String, Fontsize : CGFloat) -> NSMutableAttributedString {
    let attrs: [NSAttributedStringKey: Any] = [.font: UIFont(name: "SFUIDisplay-Regular", size: Fontsize)!, NSAttributedStringKey.foregroundColor: UIColor(red: 152.0/255.0, green: 152.0/255.0, blue: 152.0/255.0, alpha: 1.0) ]
    let boldString = NSMutableAttributedString(string:text, attributes: attrs)
    append(boldString)
    return self
}
}

Now you can Execute the function something like this to use as a globally

func FormattedString(Orange : String, WarmGrey : String ,fontsize : CGFloat) -> NSMutableAttributedString 
{
   let paragraphStyle = NSMutableParagraphStyle()
   paragraphStyle.alignment = .left
   paragraphStyle.lineSpacing = 1
   paragraphStyle.paragraphSpacing = 1
   let formattedString = NSMutableAttributedString()
   formattedString
    .DustyOrange(Orange, Fontsize: fontsize)
    .WarmGrey(WarmGrey, Fontsize: fontsize )
  formattedString.addAttributes([NSAttributedStringKey.paragraphStyle: paragraphStyle], range: NSRange(location: 0, length: formattedString.length))
   return formattedString
}

You can use globalized function like this

 yourLabelName.attributedText = FormattedString(Orange: "String with orange color", WarmGrey: " String with warm grey color.", fontsize: 11.5)

Attributed text with image

func AttributedTextwithImgaeSuffix(AttributeImage : UIImage , AttributedText : String , buttonBound : UIButton) -> NSMutableAttributedString 
 {
   let fullString = NSMutableAttributedString(string: AttributedText + "  ")
   let image1Attachment = NSTextAttachment()
   image1Attachment.bounds = CGRect(x: 0, y: ((buttonBound.titleLabel?.font.capHeight)! - 
  AttributeImage.size.height).rounded() / 2, width: 
  AttributeImage.size.width, height: AttributeImage.size.height)
  image1Attachment.image = AttributeImage
  let image1String = NSAttributedString(attachment: image1Attachment)
  fullString.append(image1String)
  fullString.append(NSAttributedString(string: ""))
  return fullString 
}

you can use "NSTextAttachment" with your button label like this.

   yourUIButton.setAttributedTitle(AttributedTextwithImgaeSuffix(AttributeImage: desiredImage, AttributedText: "desired UIButton title", buttonBound: yourUIButton), for: .normal)


回答5:

In Swift 4.x, this should look like :

        let strokeTextAttributes: [NSAttributedStringKey: Any] = [
        NSStrokeColorAttributeName: UIColor.black,
        NSForegroundColorAttributeName : UIColor.white,
        NSStrokeWidthAttributeName : -2.0,
        NSFontAttributeName : UIFont.boldSystemFont(ofSize: 18)
    ]


回答6:

if you want to change particular string value so that below answer is helpful you:-

let subStr = "Hello" let allStr = "Hello World"

    let newStr = NSMutableAttributedString(string: allStr)
    newStr.addAttribute(kCTFontAttributeName as NSAttributedStringKey, value:  UIFont.init(customFont: .MyriadPro_R, withSize: 18)!, range: (allStr as NSString).range(of: subStr))
    newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.PrimaryColor, range: (allStr as NSString).range(of: subStr))
    self.stateLbl.attributedText = newStr


回答7:

let text = systolicString + " / " + diastolicString

let newStr = NSMutableAttributedString(string: text)
// I have static ranges, but you can also extract them dynamically
let systolicRange = NSRange(location: 0, length: 2)
let backslashRange = NSRange(location: 3, length: 1)
let diastolicRange = NSRange(location: 5, length: 2)

newStr.addAttribute(NSAttributedStringKey.font, value:  UIFont.ubuntuRegular(28), range: systolicRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "042f57"), range: systolicRange)

newStr.addAttribute(NSAttributedStringKey.font, value:  UIFont.ubuntuLight(23), range: backslashRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "6485a3"), range: backslashRange)

newStr.addAttribute(NSAttributedStringKey.font, value:  UIFont.ubuntuRegular(18), range: diastolicRange)
newStr.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor(hexString: "042f57"), range: diastolicRange)
// my UILabel
valueLabel.attributedText = newStr