nslayoutmanager在UITEXTVIEW中进行行编号
我正在尝试在Swift中创建一个iOS linenumberlayoutmanger,以在TextKit 2 UitextView中使用。我的问题是,当我输入带有返回键的新行时,线号变量被覆盖。以下修订的代码示例可以复制并粘贴到要运行的ViewController中的Xcode项目中。任何建议都非常感谢。
// ViewController.swift
// tester11
//
// Created by ianshortreed on 2022/07/15.
//
import UIKit
var currentRect:CGRect!
var cgPoint:CGPoint!
extension String {
func substring(with range: NSRange) -> String {
let startIndex = index(self.startIndex, offsetBy: range.location)
let endIndex = index(startIndex, offsetBy: range.length)
//return substring(with: startIndex ..< endIndex)
return String(self[startIndex..<endIndex])
}
}
extension Collection {
var enumerated: Zip2Sequence<PartialRangeFrom<Int32>, Self> { zip(1..., self) }
}
class ViewController: UIViewController, UITextViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
createTextView()
}
func createTextView() {
var textView: UITextView!
var textStorage: NSTextStorage!
// 1
let attrs = [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), .foregroundColor: UIColor.label]
let attrString = NSAttributedString(string: "Press the return key to add a new line.", attributes: attrs)
textStorage = NSTextStorage()
textStorage.append(attrString)
let newTextViewRect = view.bounds
// 2
//let layoutManager = LineNumberLayoutManager()
let layoutManager = LineNumberLayoutManager()
// 3
let containerSize = CGSize(width: newTextViewRect.width, height: .greatestFiniteMagnitude)
let container = NSTextContainer(size: containerSize)
container.widthTracksTextView = true
layoutManager.addTextContainer(container)
textStorage.addLayoutManager(layoutManager)
// 4
textView = UITextView(frame: newTextViewRect, textContainer: container)
textView.delegate = self
textView.isScrollEnabled = true
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 9.5
//textView.layoutManager.usesFontLeading = false
textView.keyboardDismissMode = .interactive
textView.textContainerInset = UIEdgeInsets(top: 50, left: 10, bottom: 0, right: 10)
textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17)]
textView.textAlignment = NSTextAlignment.justified
textView.allowsEditingTextAttributes = true
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.dataDetectorTypes = .all
view.addSubview(textView)
// 5
textView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
textView.topAnchor.constraint(equalTo: view.topAnchor),
textView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
class LineNumberLayoutManager: NSLayoutManager {
let lineSize = CGSize(width: 8, height: 8)
var lineColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
override func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
var linenumber = 0
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
guard let textStorage = self.textStorage else { return }
enumerateLineFragments(forGlyphRange: glyphsToShow) { [self] (rect, usedRect, textContainer, glyphRange, _) in
linenumber += 1
let origin = CGPoint(x: 10, y: usedRect.origin.y + 48 + (usedRect.size.height - self.lineSize.height) / 2)
var newLineRange = NSRange(location: 0, length: 0)
if glyphRange.location > 0 {
newLineRange.location = glyphRange.location - 1
newLineRange.length = 1
}
var isNewLine = true
if newLineRange.length > 0 {
isNewLine = textStorage.string.substring(with: newLineRange) == "\n"
}
if isNewLine {
let str = textStorage.string.components(separatedBy: .newlines)
"\(linenumber)\(str)".draw(in:CGRect(origin: origin, size: lineSize))
}
}
}
}
}
I am attempting to create an iOS LineNumberLayoutManger in Swift to be used in a TextKit 2 UITextView. My problem is the line number variable is being overwritten when I enter a new line with the return key. The revised code sample below can be copied and pasted into an Xcode project in a ViewController to run. Any suggestions very much appreciated.
// ViewController.swift
// tester11
//
// Created by ianshortreed on 2022/07/15.
//
import UIKit
var currentRect:CGRect!
var cgPoint:CGPoint!
extension String {
func substring(with range: NSRange) -> String {
let startIndex = index(self.startIndex, offsetBy: range.location)
let endIndex = index(startIndex, offsetBy: range.length)
//return substring(with: startIndex ..< endIndex)
return String(self[startIndex..<endIndex])
}
}
extension Collection {
var enumerated: Zip2Sequence<PartialRangeFrom<Int32>, Self> { zip(1..., self) }
}
class ViewController: UIViewController, UITextViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
createTextView()
}
func createTextView() {
var textView: UITextView!
var textStorage: NSTextStorage!
// 1
let attrs = [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), .foregroundColor: UIColor.label]
let attrString = NSAttributedString(string: "Press the return key to add a new line.", attributes: attrs)
textStorage = NSTextStorage()
textStorage.append(attrString)
let newTextViewRect = view.bounds
// 2
//let layoutManager = LineNumberLayoutManager()
let layoutManager = LineNumberLayoutManager()
// 3
let containerSize = CGSize(width: newTextViewRect.width, height: .greatestFiniteMagnitude)
let container = NSTextContainer(size: containerSize)
container.widthTracksTextView = true
layoutManager.addTextContainer(container)
textStorage.addLayoutManager(layoutManager)
// 4
textView = UITextView(frame: newTextViewRect, textContainer: container)
textView.delegate = self
textView.isScrollEnabled = true
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 9.5
//textView.layoutManager.usesFontLeading = false
textView.keyboardDismissMode = .interactive
textView.textContainerInset = UIEdgeInsets(top: 50, left: 10, bottom: 0, right: 10)
textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17)]
textView.textAlignment = NSTextAlignment.justified
textView.allowsEditingTextAttributes = true
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.dataDetectorTypes = .all
view.addSubview(textView)
// 5
textView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
textView.topAnchor.constraint(equalTo: view.topAnchor),
textView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
class LineNumberLayoutManager: NSLayoutManager {
let lineSize = CGSize(width: 8, height: 8)
var lineColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
override func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
var linenumber = 0
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
guard let textStorage = self.textStorage else { return }
enumerateLineFragments(forGlyphRange: glyphsToShow) { [self] (rect, usedRect, textContainer, glyphRange, _) in
linenumber += 1
let origin = CGPoint(x: 10, y: usedRect.origin.y + 48 + (usedRect.size.height - self.lineSize.height) / 2)
var newLineRange = NSRange(location: 0, length: 0)
if glyphRange.location > 0 {
newLineRange.location = glyphRange.location - 1
newLineRange.length = 1
}
var isNewLine = true
if newLineRange.length > 0 {
isNewLine = textStorage.string.substring(with: newLineRange) == "\n"
}
if isNewLine {
let str = textStorage.string.components(separatedBy: .newlines)
"\(linenumber)\(str)".draw(in:CGRect(origin: origin, size: lineSize))
}
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论