nslayoutmanager在UITEXTVIEW中进行行编号

发布于 2025-02-13 06:30:03 字数 5681 浏览 0 评论 0原文

我正在尝试在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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文