Skip to content

Instantly share code, notes, and snippets.

@ArtiomKha
Created February 10, 2023 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ArtiomKha/3ff1d980b181bc5efde8aa1d1edbbfee to your computer and use it in GitHub Desktop.
Save ArtiomKha/3ff1d980b181bc5efde8aa1d1edbbfee to your computer and use it in GitHub Desktop.
Gist with source code for the Medium article about NSAttributedString
import UIKit
struct MovieInfo {
let title: String
let description: String
let cast: [ActorInfo]
}
struct ActorInfo {
let character: String
let name: String
let revenue: String
}
struct Colors {
static let textPrimary: UIColor = #colorLiteral(red: 0.172114253, green: 0.1933369339, blue: 0.2129674852, alpha: 1)
static let textSecondaty: UIColor = #colorLiteral(red: 0.2862745098, green: 0.3137254902, blue: 0.3411764706, alpha: 1)
static let greenText: UIColor = #colorLiteral(red: 0.1764705882, green: 0.4156862745, blue: 0.3098039216, alpha: 1)
}
struct Fonts {
static let title: UIFont = .systemFont(ofSize: 24, weight: .bold)
static let description: UIFont = .systemFont(ofSize: 16, weight: .regular)
static let subtitle: UIFont = .systemFont(ofSize: 18, weight: .bold)
static let actorName: UIFont = .systemFont(ofSize: 16, weight: .semibold)
static let actorCharacter: UIFont = .systemFont(ofSize: 16, weight: .regular)
static let actorRevenue: UIFont = .systemFont(ofSize: 16, weight: .medium)
}
class ViewController: UIViewController {
let movie: MovieInfo = MovieInfo(
title: "Avengers: Infinity War",
description: "The Avengers and their allies must be willing to sacrifice all in an attempt to defeat the powerful Thanos before his blitz of devastation and ruin puts an end to the universe.",
cast: [ActorInfo(character: "Tony Stark", name: "Robert Downey Jr.", revenue: "$ 75 000 000"),
ActorInfo(character: "Thor", name: "Chris Hemsworth", revenue: "$ 15 000 000"),
ActorInfo(character: "Captain America", name: "Chris Evans", revenue: "$ 15 000 000"),
ActorInfo(character: "Spider-Man", name: "Tom Holland", revenue: "$ 3 000 000")]
)
var contentView: MainView {
view as! MainView
}
override func loadView() {
super.loadView()
view = MainView()
}
override func viewDidLoad() {
super.viewDidLoad()
contentView.set(movie)
}
}
class MainView: UIView {
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
return label
}()
init() {
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setup() {
backgroundColor = .white
addSubview(label)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 32),
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
label.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -32)
])
}
func set(_ movie: MovieInfo) {
let result = NSMutableAttributedString()
result.append(NSAttributedString(
string: "\(movie.title)\n",
attributes: [.font : Fonts.title, .foregroundColor : Colors.textPrimary])
)
result.append(.spacing(8))
result.append(NSAttributedString(
string: "\(movie.description)\n",
attributes: [.font : Fonts.description, .foregroundColor : Colors.textSecondaty])
)
result.append(.spacing(16))
result.append(NSAttributedString(
string: "Top cast:\n",
attributes: [.font : Fonts.subtitle, .foregroundColor : Colors.textPrimary])
)
result.append(.spacing(4))
movie.cast.forEach { result.append(createTextBlock(for: $0)) }
label.attributedText = result
}
func createTextBlock(for actor: ActorInfo) -> NSAttributedString {
let result = NSMutableAttributedString()
result.append(NSAttributedString(
string: actor.name + "\n",
attributes: [.font : Fonts.actorName,
.foregroundColor : Colors.textPrimary])
)
result.append(NSAttributedString(
string: actor.character + ", ",
attributes: [.font : Fonts.actorCharacter,
.foregroundColor : Colors.textSecondaty])
)
result.append(NSAttributedString(
string: actor.revenue + "\n",
attributes: [.font : Fonts.actorRevenue,
.foregroundColor : Colors.greenText])
)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 4
result.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: result.length))
result.append(.spacing(12))
return result
}
}
extension NSAttributedString {
static func spacing(_ size: CGFloat) -> NSAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = size
paragraphStyle.maximumLineHeight = size
let spacing = NSAttributedString(string: "\n", attributes: [.paragraphStyle : paragraphStyle])
return spacing
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment