Created
February 10, 2023 10:42
-
-
Save ArtiomKha/3ff1d980b181bc5efde8aa1d1edbbfee to your computer and use it in GitHub Desktop.
Gist with source code for the Medium article about NSAttributedString
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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