Post

Replies

Boosts

Views

Activity

Reply to How can we performantly scroll to a target location using TextKit 2?
A hacky way: Tested on a MacBook Mid 2014; Scrolling takes approximately 0.001 seconds. var counter = 0 override func moveToEndOfDocument(_ sender: Any?) { let measureStartDate = Date() resetScrollSettings() scrollTextView() print("⏰ scrolling took \(Date().timeIntervalSince(measureStartDate))s") } func resetScrollSettings() { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(scrollTextView), object: nil) counter = 0 } @objc func scrollTextView() { /// Change this number to ensure that all necessary recursions are executed let magicNumber = 50 if counter > magicNumber { return } else { counter += 1 } let range = NSTextRange(location: textLayoutManager.documentRange.endLocation) textLayoutManager.ensureLayout(for: range) let targetLocation = textLayoutManager.documentRange.endLocation let beforeTargetLocation = textLayoutManager.location(targetLocation, offsetBy: -1)! textLayoutManager.textViewportLayoutController.layoutViewport() guard let textLayoutFragment = textLayoutManager.textLayoutFragment(for: beforeTargetLocation) else { return } guard let textLineFragment = textLayoutFragment.textLineFragment(for: targetLocation, isUpstreamAffinity: true) else { return } let lineFrame = textLayoutFragment.layoutFragmentFrame let lineFragmentFrame = textLineFragment.typographicBounds.offsetBy(dx: 0, dy: lineFrame.minY) scrollToVisible(lineFragmentFrame) perform(#selector(scrollTextView), with: nil, afterDelay: 0.001) }
Aug ’24
Reply to How can we performantly scroll to a target location using TextKit 2?
This new approach will simplify your original code, allowing you to move to a specific end location. Note: Efficiency depends on how far the target end location is from the start of the document. override func moveToEndOfDocument(_ sender: Any?) { moveToEndLocation(textLayoutManager.documentRange.endLocation) } func moveToEndLocation(_ targetEndLocation: NSTextLocation) { var lineFragmentFrame: CGRect = .null textLayoutManager.enumerateTextLayoutFragments(from: textLayoutManager.documentRange.location, options: [.ensuresLayout]) { layoutFragment in if layoutFragment.rangeInElement.endLocation.compare(targetEndLocation) != .orderedAscending { lineFragmentFrame = layoutFragment.layoutFragmentFrame return false } return true } textLayoutManager.textViewportLayoutController.layoutViewport() self.scrollToVisible(lineFragmentFrame) }
Aug ’24