Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edit - still not a complete example, but this seems much more straightforward...
- // ------------------------------------------------
- // UIScrollView subclass
- // ------------------------------------------------
- class MyScrollView: UIScrollView, UIScrollViewDelegate {
- var textView: UITextView!
- var oneCharSize: CGSize = .zero
- let font = UIFont.monospacedSystemFont(ofSize: 23, weight: .regular)
- let numCols: Int = 80
- let numRows: Int = 25
- override init(frame: CGRect) {
- super.init(frame: frame)
- commonInit()
- }
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- commonInit()
- }
- func commonInit() {
- setupTextView()
- delegate = self
- }
- func setupTextView() {
- // My text view is going to contain a maximum of 80x25 characters, so here
- // I am calculating how much space that is going to take up
- let line = String(repeating: "a", count: numCols + 1)
- let fullText = Array(repeating: line, count: numRows + 1).joined(separator: "\n")
- let unroundedSize = (fullText as NSString).size(withAttributes: [
- .font: font
- ])
- let size = CGSize(width: ceil(unroundedSize.width), height: ceil(unroundedSize.height))
- // get the size of one character
- let unroundedSizeC = ("a" as NSString).size(withAttributes: [
- .font: font
- ])
- oneCharSize = CGSize(width: ceil(unroundedSizeC.width), height: ceil(unroundedSizeC.height))
- textView = UITextView(frame: CGRect(origin: .zero, size: size))
- contentSize = size
- addSubview(textView)
- textView.spellCheckingType = .no
- textView.dataDetectorTypes = []
- textView.font = font
- // sample text to start with
- textView.text = """
- UILabel
- A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.
- UIButton
- Displays a plain styled button that can have a title, subtitle, image, and other appearance properties.
- """
- // the text view does not need to scroll. All the scrolling is done
- // by the scroll view
- textView.isScrollEnabled = false
- // so we can see it
- textView.backgroundColor = .yellow
- }
- override func scrollRectToVisible(_ rect: CGRect, animated: Bool) {
- if !textView.isFirstResponder {
- return super.scrollRectToVisible(rect, animated: animated)
- }
- if let selectedTextRange = textView.selectedTextRange {
- // this is the NEW caret position
- let caretPositionRect = textView.caretRect(for: selectedTextRange.start)
- var charRect = CGRect(origin: caretPositionRect.origin, size: oneCharSize)
- let visibleRect = CGRect(origin: contentOffset, size: frame.size)
- if !visibleRect.contains(charRect) {
- if charRect.origin.x - contentOffset.x < 0 {
- charRect.origin.x = 0
- }
- super.scrollRectToVisible(charRect, animated: animated)
- }
- }
- }
- }
- // ------------------------------------------------
- // example view controller
- // ------------------------------------------------
- class MyViewController: UIViewController {
- var scrollView: MyScrollView!
- var textView: UITextView!
- override func viewDidLoad() {
- scrollView = MyScrollView()
- scrollView.backgroundColor = .green
- scrollView.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(scrollView)
- let g = view.safeAreaLayoutGuide
- NSLayoutConstraint.activate([
- scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20),
- scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20),
- scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20),
- // scroll view height = 240
- // because we're not addressing keyboard cover at this time
- scrollView.heightAnchor.constraint(equalToConstant: 240.0),
- ])
- }
- }
- // ------------------------------------------------
- // UIScrollView subclass (originally posted)
- // ------------------------------------------------
- class OriginalMyScrollView: UIScrollView {
- var textView: UITextView!
- var oneCharSize: CGSize = .zero
- let font = UIFont.monospacedSystemFont(ofSize: 23, weight: .regular)
- override init(frame: CGRect) {
- super.init(frame: frame)
- commonInit()
- }
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- commonInit()
- }
- func commonInit() {
- setupTextView()
- }
- func setupTextView() {
- // My text view is going to contain a maximum of 80x25 characters, so here
- // I am calculating how much space that is going to take up
- let line = String(repeating: "a", count: 81)
- let fullText = Array(repeating: line, count: 26).joined(separator: "\n")
- let unroundedSize = (fullText as NSString).size(withAttributes: [
- .font: font
- ])
- let size = CGSize(width: ceil(unroundedSize.width), height: ceil(unroundedSize.height))
- let unroundedCharSize = ("W" as NSString).size(withAttributes: [
- .font: font
- ])
- oneCharSize = CGSize(width: ceil(unroundedCharSize.width), height: ceil(unroundedCharSize.height))
- textView = UITextView(frame: CGRect(origin: .zero, size: size))
- contentSize = size
- addSubview(textView)
- textView.spellCheckingType = .no
- textView.dataDetectorTypes = []
- textView.font = font
- // dummy text
- textView.text = """
- UILabel
- A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.
- UIButton
- Displays a plain styled button that can have a title, subtitle, image, and other appearance properties.
- """
- // the text view do not need to scroll. All the scrolling is done
- // by the scroll view
- textView.isScrollEnabled = false
- // so we can see it
- textView.backgroundColor = .yellow
- }
- override func scrollRectToVisible(_ rect: CGRect, animated: Bool) {
- if let selectedTextRange = textView.selectedTextRange {
- let caretPositionRect = textView.caretRect(for: selectedTextRange.start)
- var x: CGFloat = contentOffset.x
- if caretPositionRect.minX - contentOffset.x < oneCharSize.width {
- x += (caretPositionRect.minX - contentOffset.x) - oneCharSize.width
- x = max(0, x)
- } else if ((caretPositionRect.minX - contentOffset.x) - frame.width) > -oneCharSize.width {
- x = caretPositionRect.minX - frame.width
- x += oneCharSize.width
- x = min(x, contentSize.width - frame.width)
- }
- contentOffset.x = x
- }
- }
- }
Add Comment
Please, Sign In to add comment