-2

I have a class called "rectangle" to make custom UILabels. I override "draw" in the rectangle class. When I instantiate the label, I want the FIRST line of text to show up in bolded font. I know how to solve this by manually getting the range for each string... however, I have more than 300 strings to do. The strings are currently in an array, formatted like so: "Happy \n Birthday". How can I make the word "Happy" bold?

var messageText = "Happy \n Birthday"
let rectanglePath = UIBezierPath(rect: rectangleRect)
context.saveGState()
UIColor.white.setFill()
rectanglePath.fill()
context.restoreGState()

darkPurple.setStroke()
rectanglePath.lineWidth = 0.5
rectanglePath.lineCapStyle = .square
rectanglePath.lineJoinStyle = .round
rectanglePath.stroke()

let rectangleStyle = NSMutableParagraphStyle()
rectangleStyle.alignment = .center
let rectangleFontAttributes = [
  .font: UIFont.myCustomFont(true),
  .foregroundColor: UIColor.black,
  .paragraphStyle: rectangleStyle,
  ] as [NSAttributedString.Key: Any]

let rectangleTextHeight: CGFloat = messageText.boundingRect(with: CGSize(width: rectangleRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: rectangleFontAttributes, context: nil).height
context.saveGState()
context.clip(to: rectangleRect)
messageText.draw(in: CGRect(x: rectangleRect.minX, y: rectangleRect.minY + (rectangleRect.height - rectangleTextHeight) / 2, width: rectangleRect.width, height: rectangleTextHeight), withAttributes: rectangleFontAttributes)
context.restoreGState()
taralee98
  • 127
  • 1
  • 12

1 Answers1

1

You can find the first by separating the string by newline:

let firstLine = "Happy \n Birthday".split(separator: "\n").first

This will give you the first line of the string. (long text multi lining doesn't count) then you can find the range using this and apply the bold effect.

How this works:

  • You need to set the label the way that accepts multiline:
  • Find the range of first line
  • Convert it to nsRange
  • Apply attributes to the range

Here is a fully working example:

import UIKit
import PlaygroundSupport

extension StringProtocol where Index == String.Index {

    func nsRange(from range: Range<Index>) -> NSRange {
        return NSRange(range, in: self)
    }
}

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let label = UILabel()
        label.numberOfLines = 0
        label.text = "Happy \n Birthday"
        label.textColor = .black

        let text = "Happy \n Birthday"
        let attributedString = NSMutableAttributedString(string: text)
        let firstLine = text.split(separator: "\n").first!
        let range = text.range(of: firstLine)!
        attributedString.addAttributes([.font : UIFont.boldSystemFont(ofSize: 14)], range: text.nsRange(from: range))
        label.attributedText = attributedString
        label.sizeToFit()

        view.addSubview(label)
        self.view = view
    }
}

PlaygroundPage.current.liveView = MyViewController()
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278