рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди
рджрд┐рдпрд╛: рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдкрд╛рдаред
рдЦреЛрдЬреЗрдВ: рдЦреВрдмрд╕реВрд░рддреА рд╕реЗ рдбрд┐рдЬрд╛рдЗрди рдХреА рдЧрдИ рдкреГрд╖реНрдарднреВрдорд┐ред
рд╣рд╛рдБ, рдпрд╣ рдПрдХ рдШрдВрдЯрд╛ рд╣реИ, рдореИрдВрдиреЗ рд╕реЛрдЪрд╛ред "рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯреЗрдб рдЯреИрдХреНрд╕реНрдЯ рдореЗрдВ рдмреИрдХрдЧреНрд░рд╛рдЙрдВрдб рдХреМрд░ рд▓рдЧрд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред" рд▓реЗрдХрд┐рди рдЗрддрдирд╛ рд╣реА рдХрд╛рдлреА рдирд╣реАрдВ рдерд╛ред рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдорд╛рдирдХ рдЪрдпрди рдПрдХ рднрд░рд╛ рд╣реБрдЖ рдЖрдпрдд рд╣реИред рдмрджрд╕реВрд░рддред рд╕рдорд╛рдзрд╛рди - рдЖрдкрдХреЛ рдПрдХ рдХрд╕реНрдЯрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ! рдЗрд╕рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рдХрд╛рдВрдЯреЗрджрд╛рд░ рд░рд╛рд╕реНрддреЗ рдиреЗ рдореБрдЭреЗ рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрд░рд┐рдд рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдЖрдиреЗ рд╡рд╛рд▓реА рдкреАрдврд╝рд┐рдпреЛрдВ рдХреЛ рдЗрддрдирд╛ рдиреБрдХрд╕рд╛рди рди рдЙрдард╛рдирд╛ рдкрдбрд╝реЗред рд░реБрдЪрд┐, рдореИрдВ рдмрд┐рд▓реНрд▓реА рдХреЗ рд▓рд┐рдП рдкреВрдЫрдирд╛ред
рд╕реНрд╡реАрдХрд╛рд░
рдкрд╣рд▓реА рдХреНрд░рд┐рдпрд╛ рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рдЗрдВрдЯрд░рдиреЗрдЯ рдХреЙрд▓ рдереА рдЬрд┐рд╕рдореЗрдВ рдЙрдЪрд┐рдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдкреНрд░рд╢реНрди рдерд╛ред рдЬрд╡рд╛рдм рдореЗрдВ, рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рдереЗред рд╕рдмрд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд рдореЗрдВ, рд╕рдм рдХреБрдЫ fillBackgroundRectArray рд╡рд┐рдзрд┐ рдХреЗ рдУрд╡рд░рд░рд╛рдЗрдб рдХреЗ рд▓рд┐рдП рдЖрдпрд╛ рдерд╛ред рд╕рд╛рдорд╛рдиреНрдп рдЬреАрд╡рди рдореЗрдВ, рд╡рд╣ рдКрдкрд░ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рдПрдЯреНрд░рд┐рдмреНрдпреВрдЯ рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд╛рда рдХреЛ рд░рдВрдЧ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЬрд╛рдирд╡рд░ рд╣реИ, рдореИрдВрдиреЗ рдЗрд╕ рдЙрдореНрдореАрдж рдореЗрдВ рддреИрдпрд╛рд░ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдХрд┐ рдХрд╛рдо рдЕрднреА рднреА рдХреБрдЫ рдШрдВрдЯреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реЛрдЧрд╛ред рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд┐рдпрд╛ рдлреИрд╕рд▓реЗ рдиреЗ рдмреБрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд┐рдпрд╛ред
рдкреНрд░рд▓реЗрдЦрди рд╕рдм рдХреБрдЫ рд╣реИред
рдлрд┐рд░ рд╕реЗ рдРрд╕рд╛ рди рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реБрдП, рдореИрдВрдиреЗ рдкреНрд░рд▓реЗрдЦрди рдХреА рдУрд░ рд░реБрдЦ рдХрд┐рдпрд╛ред рдЗрд╕рд╕реЗ рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рдХрд┐ UITextView рддреАрди рд╕рд╛рдерд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕рдВрдЪрд╛рд▓рд┐рдд рдкрд╛рда рдХреЗ рд▓рд┐рдП UIScrollView рдХрд╛ рдПрдХ рд╕рд░рд▓ рд╡рдВрд╢рдЬ рд╣реИ:
- NSTextStorage - рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ NSMutableAtributedString рдкрд░ рдПрдХ рдЖрд╡рд░рдг, рдкрд╛рда рдФрд░ рдЗрд╕рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ;
- NSTextContainer - NSObject, рдЙрд╕ рдЬреНрдпрд╛рдорд┐рддреАрдп рдЖрдХреГрддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдкрд╛рда рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдпрд╣ рдПрдХ рдЖрдпрдд рд╣реИ, рдЖрдк рдХреБрдЫ рднреА рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ;
- NSLayoutManager - рдкрд╣рд▓реЗ рджреЛ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рддрд╛ рд╣реИ: рдкрд╛рда рд▓реЗрддрд╛ рд╣реИ, рдЗрдВрдбреЗрдВрдЯ рдХрд░рддрд╛ рд╣реИ, рдкреИрд░рд╛рдЧреНрд░рд╛рдл рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╣рдореЗрдВ рдЙрд╕ рднрд░рдг рдХреЗ рд▓рд┐рдП рднреА рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдПред
рдПрд▓реНрдЧреЛрд░рд┐рджрдо рд╢рд╛рдВрдд рд╣реИрдВ
рдирддреАрдЬрддрди, рдХрд╛рд░реНрдп рдПрдХ рдХрд╕реНрдЯрдо NSLayoutManadger рдмрдирд╛рдиреЗ рдФрд░ рдЗрд╕рдореЗрдВ рд╡рд╛рдВрдЫрд┐рдд рд╡рд┐рдзрд┐ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдмрд▓рддрд╛ рд╣реИред
class SelectionLayoutManager: NSLayoutManager { override func fillBackgroundRectArray(_ rectArray: UnsafePointer<CGRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: UIColor) { }
рдореБрдЦреНрдп рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ, fillBackgroundRectArray рд╢рдмреНрджреЛрдВ рдХреА рдЖрдпрддреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдкреЗрдВрдЯ рдХрд░рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рдЖрдВрдХрдбрд╝реЗ, рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдПрдХ рдЬрдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рдПрдХ рдкрдВрдХреНрддрд┐ рдХреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╣рд┐рд╕реНрд╕реЗ рд╣реИрдВ, рдХрд╣реАрдВ рднреА рдЙрдиреНрд╣реЗрдВ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдерд╛ред рдЗрд╕рд▓рд┐рдП рд╕рдордп рдХрд╛ рдЙрдк-рдпреЛрдЧ: рд╕рд╣реА рдЖрдпрддреЛрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ рдЬреЛ рд▓рд╛рдЗрди рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рд╢реБрд░реВ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХреЗ рдЕрдВрдд рддрдХ рдЕрдкреНрд░рдЪрд▓рд┐рдд рд╣реЛрддреЗ рд╣реИрдВред
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рд╡рд╛рд▓реА рд╡рд┐рдзрд┐ рдирд┐рдореНрди рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рд╣реИ: рдпрд╣ рдкреИрд░рд╛рдЧреНрд░рд╛рдл рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдПрдХ рд▓реВрдк рдореЗрдВ рдЬрд╛рддреА рд╣реИ рдФрд░ рдЬрд╛рдВрдЪрддреА рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд▓рд╛рдЗрди рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдлрд┐рдЯ рд╣реЛрдЧреА рдпрджрд┐ рдЕрдЧрд▓рд╛ рд╢рдмреНрдж рдЗрд╕рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ? рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдпрд╣ рдПрдХ рдЕрд▓рдЧ рдкреВрд░реНрдг рд░реЗрдЦрд╛ рд╣реИ, рдЕрдЧрд▓реЗ рдкрд░ рдЬрд╛рдПрдВред рдпрджрд┐ рдРрд╕рд╛ рд╣реИ, рддреЛ рдЕрдЧрд▓реЗ рд╢рдмреНрдж рдХреЛ рд▓реЗрдВ рдФрд░ рд╕реНрдерд┐рддрд┐ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЬрд╛рдВрдЪреЗрдВред рд╣рд╛рдВ, рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдмреЗрд╣рдж рд╕рд░рд▓ рд╣реИ, рдПрдХ рдкреБрдирд░рд╛рд╡рд░реНрддреА рд╡рд┐рдзрд┐ рдмрдирд╛рдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдерд╛, рд▓реЗрдХрд┐рди рдЕрднреА рддрдХ рд╣рд╛рде рдирд╣реАрдВ рдкрд╣реБрдВрдЪреЗ рд╣реИрдВред рдЯрд┐рдкреНрдкрдгреА рдореЗрдВ, рдореИрдВ рдЖрдкрдХреЗ рдЕрдиреБрдХреВрд▓рд┐рдд рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд▓рд┐рдП рдкреВрдЫрддрд╛ рд╣реВрдВред
private func detectLines(from string: String, width: CGFloat, font: UIFont) -> [String] { var strings: [String] = [] var cumulativeString = "" let words = string.components(separatedBy: CharacterSet.whitespaces) for word in words { let checkingString = cumulativeString + word if checkingString.size(withFont: font).width < width { cumulativeString.append(word) } else { if cumulativeString.isNotEmpty { strings.append(cumulativeString) } if word.size(withFont: font).width < width { cumulativeString = word } else { var stringsFromWord: [String] = [] var handlingWord = word while handlingWord.isNotEmpty { let fullFillString = detectFullFillString(from: handlingWord, width: width, font: font) stringsFromWord.append(fullFillString) handlingWord = word.replacingOccurrences(of: stringsFromWord.reduce("") { $0 + $1 }, with: "") } stringsFromWord.removeLast() strings.append(contentsOf: stringsFromWord) let remainString = word.replacingOccurrences(of: stringsFromWord.reduce("") { $0 + $1 }, with: "") cumulativeString = remainString } } } if cumulativeString.isNotEmpty { strings.append(cumulativeString) } return strings }
рдпрд╣ рд╢рдмреНрджреЛрдВ рдХреЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдкрд░ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╕реНрд╡рдпрдВ рджреНрд╡рд╛рд░рд╛ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред UITextView рдЙрдирдХреЗ рд╕рд╛рде рдмрд╣реБрдд рд╕рд░рд▓рддрд╛ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ - рдЙрд╕ рд╣рд┐рд╕реНрд╕реЗ рдХреА рдЕрдЧрд▓реА рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рдЬреЛ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рдерд╛ред рд╣рдо рдЕрдиреБрдХреНрд░рдорд┐рдХ рдорд╛рд░реНрдЧ рдХреЗ рд╕рдорд╛рди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде рдПрдХ рдЕрд▓рдЧ рд╡рд┐рдзрд┐ рдореЗрдВ рдЗрд╕ рддрд░реНрдХ рдХреА рдирдХрд▓ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкреНрд░рддреАрдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВред рдЗрд╕рдореЗрдВ рдХреНрдпрд╛ рд╢рд╛рдорд┐рд▓ рдерд╛: рдПрдХ рдкреВрд░реА рд▓рд╛рдЗрди, рдмрд╛рдХреА - рдпрд╛ рддреЛ рдПрдХ рдкреВрд░реА рд▓рд╛рдЗрди, рдПрдХ рдмрд╣реБрдд рд▓рдВрдмреЗ рд╢рдмреНрдж рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╛ рдПрдХ рдирдИ рд▓рд╛рдЗрди рдкрд░ рд╕рд┐рд░реНрдл рдПрдХ рдирдпрд╛ рд╢рдмреНрджред
private func detectFullFillString(from word: String, width: CGFloat, font: UIFont) -> String { var string = "" for character in word { let checkingString = string.appending(String(character)) if checkingString.size(withFont: font).width > width { break } else { string.append(contentsOf: String(character)) } } return string }
рдбрд┐рдЯреЗрд▓рд▓рд╛рдЗрди рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк (рд╕реЗ: рдЪреМрдбрд╝рд╛рдИ: рдлрд╝реЙрдиреНрдЯ :) рд╡рд┐рдзрд┐, рд╣рдореЗрдВ рдЙрди рддрд╛рд░реЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдорд┐рд▓рддреА рд╣реИ рдЬреЛ рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реЛрддреА рд╣реИрдВред рдЕрдЧрд▓рд╛, рдлрд╝реНрд░реЗрдо рд╕реЗ (рд▓рд╛рдЗрдиреЛрдВ рдХреЗ рд▓рд┐рдП: рдЪреМрдбрд╝рд╛рдИ: рдлрд╝реЙрдиреНрдЯ) рд╡рд┐рдзрд┐, рд╣рдореЗрдВ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХреЛрдВ рдФрд░ рд░реЗрдЦрд╛ рдЖрдХрд╛рд░реЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдорд┐рд▓рддреА рд╣реИред
private func frames(for lines: [String], width: CGFloat, font: UIFont) -> [CGRect] { var rects: [CGRect] = [] let stringsSizes = lines.map { $0.size(withFont: font) } stringsSizes.forEach { let rect = CGRect(origin: CGPoint(x: (width - $0.width) / 2, y: $0.height * CGFloat(rects.count)), size: $0) rects.append(rect) } return rects }
рд╕реБрдВрджрд░рддрд╛ рд▓рд╛рдирд╛
рдЙрдкрд╢реАрд░реНрд╖рдХ рд╕рдВрдЦреНрдпрд╛ рджреЛ: рдЖрдпрддреЛрдВ рдкрд░ рдкреЗрдВрдЯ рдХрд░реЗрдВред "рд╕реБрдВрджрд░" рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛ рдХреЗ рддрд╣рдд рдЧреЛрд▓ рдХреЛрдиреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдпрдд рдХреЗ рдЪрдпрдирд┐рдд рд░рдВрдЧ рдХреЛ рднрд░рдирд╛ рдерд╛ред рд╕рдорд╛рдзрд╛рди: UIBezierPath рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рд╕рдВрджрд░реНрдн рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдкрд░ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд░рдд рдЦреАрдВрдЪреЗрдВред рдЬреЛрдбрд╝реЛрдВ рдХреЛ рдмреЗрд╣рддрд░ рджрд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЖрдпрдд рдХреЗ рдХрд┐рдирд╛рд░реЛрдВ рдХреЛ рдЧреЛрд▓ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рдЪреМрдбрд╝рд╛рдИ рдореЗрдВ рдЫреЛрдЯрд╛ рд╣реИред рд╡рд┐рдзрд┐ рд╕рд░рд▓ рд╣реИ: рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдЖрдпрдд рдХреЗ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рд╕рдореЛрдЪреНрдЪ рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред
private func path(from rects: [CGRect], cornerRadius: CGFloat, horizontalInset: CGFloat) -> CGPath { let path = CGMutablePath() rects.enumerated().forEach { (index, rect) in let hasPrevious = index > 0 let isPreviousWider = hasPrevious ? rects[index - 1].width >= rect.width || abs(rects[index - 1].width - rect.width) < 5 : false let hasNext = index != rects.count - 1 let isNextWider = hasNext ? rects[index + 1].width >= rect.width || abs(rects[index + 1].width - rect.width) < 5 : false path.move(to: CGPoint(x: rect.minX - horizontalInset + (isPreviousWider ? 0 : cornerRadius), y: rect.minY))
рдЕрдЧрд▓рд╛, рдбреНрд░рд╛ (_: рд░рдВрдЧ :) рд╡рд┐рдзрд┐ рдореЗрдВ, рдкрде рднрд░реЗрдВред
private func draw(_ path: CGPath, color: UIColor) { color.set() if let ctx = UIGraphicsGetCurrentContext() { ctx.setAllowsAntialiasing(true) ctx.setShouldAntialias(true) ctx.addPath(path) ctx.drawPath(using: .fillStroke) } }
FillBackgroundRectArray рд╡рд┐рдзрд┐ рдХрд╛ рдкреВрд░рд╛ рдХреЛрдб (_: рдЧрд┐рдирддреА: forCharacterRange: рд░рдВрдЧ :)
override func fillBackgroundRectArray(_ rectArray: UnsafePointer<CGRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: UIColor) { let cornerRadius: CGFloat = 8 let horizontalInset: CGFloat = 5 guard let font = (textStorage?.attributes(at: 0, effectiveRange: nil).first { $0.key == .font })?.value as? UIFont, let textContainerWidth = textContainers.first?.size.width else { return }
рд╣рдо рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВред рдорд╣рд╛рди рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ: рд░рд┐рд╡рд╛рдЬ рдХрднреА-рдХрднреА рдореБрд╢реНрдХрд┐рд▓ рдФрд░ рдмреАрдорд╛рд░ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЬрдм рдпрд╣ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рддреЛ рдпрд╣ рдХрд┐рддрдирд╛ рд╕реБрдВрджрд░ рд╣реИред рдХрд╛рд╕реНрдЯ, рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИред
рдкреВрд░реНрдг рдХреЛрдб рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
SelectionLayoutManager ред
рд╕рдВрджрд░реНрдн
- NSLayoutManager
- NSTextContainer
- NSTextView
- рдкрд╛рда рдХреЛ рдЖрдХрд░реНрд╖рд┐рдд рдФрд░ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рда рдХрд┐рдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛