Don_Mag

horizontal scroll textview in scrollview

Jan 18th, 2022 (edited)
1,206
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 6.63 KB | None | 0 0
  1. // Edit - still not a complete example, but this seems much more straightforward...
  2.  
  3. // ------------------------------------------------
  4. // UIScrollView subclass
  5. // ------------------------------------------------
  6. class MyScrollView: UIScrollView, UIScrollViewDelegate {
  7.    
  8.     var textView: UITextView!
  9.    
  10.     var oneCharSize: CGSize = .zero
  11.    
  12.     let font = UIFont.monospacedSystemFont(ofSize: 23, weight: .regular)
  13.  
  14.     let numCols: Int = 80
  15.     let numRows: Int = 25
  16.    
  17.     override init(frame: CGRect) {
  18.         super.init(frame: frame)
  19.         commonInit()
  20.     }
  21.     required init?(coder: NSCoder) {
  22.         super.init(coder: coder)
  23.         commonInit()
  24.     }
  25.     func commonInit() {
  26.         setupTextView()
  27.         delegate = self
  28.     }
  29.     func setupTextView() {
  30.        
  31.         // My text view is going to contain a maximum of 80x25 characters, so here
  32.         // I am calculating how much space that is going to take up
  33.  
  34.         let line = String(repeating: "a", count: numCols + 1)
  35.         let fullText = Array(repeating: line, count: numRows + 1).joined(separator: "\n")
  36.         let unroundedSize = (fullText as NSString).size(withAttributes: [
  37.             .font: font
  38.         ])
  39.         let size = CGSize(width: ceil(unroundedSize.width), height: ceil(unroundedSize.height))
  40.  
  41.        
  42.         // get the size of one character
  43.         let unroundedSizeC = ("a" as NSString).size(withAttributes: [
  44.             .font: font
  45.         ])
  46.        
  47.         oneCharSize = CGSize(width: ceil(unroundedSizeC.width), height: ceil(unroundedSizeC.height))
  48.        
  49.         textView = UITextView(frame: CGRect(origin: .zero, size: size))
  50.         contentSize = size
  51.        
  52.         addSubview(textView)
  53.        
  54.         textView.spellCheckingType = .no
  55.         textView.dataDetectorTypes = []
  56.         textView.font = font
  57.  
  58.         // sample text to start with
  59.         textView.text = """
  60. UILabel
  61.  
  62. 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.
  63.  
  64. UIButton
  65.  
  66. Displays a plain styled button that can have a title, subtitle, image, and other appearance properties.
  67.  
  68. """
  69.        
  70.         // the text view does not need to scroll. All the scrolling is done
  71.         // by the scroll view
  72.         textView.isScrollEnabled = false
  73.  
  74.         // so we can see it
  75.         textView.backgroundColor = .yellow
  76.        
  77.     }
  78.  
  79.     override func scrollRectToVisible(_ rect: CGRect, animated: Bool) {
  80.        
  81.         if !textView.isFirstResponder {
  82.             return super.scrollRectToVisible(rect, animated: animated)
  83.         }
  84.            
  85.         if let selectedTextRange = textView.selectedTextRange {
  86.            
  87.             // this is the NEW caret position
  88.             let caretPositionRect = textView.caretRect(for: selectedTextRange.start)
  89.            
  90.             var charRect = CGRect(origin: caretPositionRect.origin, size: oneCharSize)
  91.            
  92.             let visibleRect = CGRect(origin: contentOffset, size: frame.size)
  93.            
  94.             if !visibleRect.contains(charRect) {
  95.                 if charRect.origin.x - contentOffset.x < 0 {
  96.                     charRect.origin.x = 0
  97.                 }
  98.                 super.scrollRectToVisible(charRect, animated: animated)
  99.             }
  100.            
  101.         }
  102.        
  103.     }
  104.    
  105. }
  106.  
  107. // ------------------------------------------------
  108. // example view controller
  109. // ------------------------------------------------
  110. class MyViewController: UIViewController {
  111.    
  112.     var scrollView: MyScrollView!
  113.     var textView: UITextView!
  114.    
  115.     override func viewDidLoad() {
  116.        
  117.         scrollView = MyScrollView()
  118.         scrollView.backgroundColor = .green
  119.         scrollView.translatesAutoresizingMaskIntoConstraints = false
  120.         view.addSubview(scrollView)
  121.         let g = view.safeAreaLayoutGuide
  122.         NSLayoutConstraint.activate([
  123.             scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20),
  124.             scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20),
  125.             scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20),
  126.  
  127.             // scroll view height = 240
  128.             //  because we're not addressing keyboard cover at this time
  129.             scrollView.heightAnchor.constraint(equalToConstant: 240.0),
  130.  
  131.         ])
  132.     }
  133.  
  134. }
  135.  
  136. // ------------------------------------------------
  137. // UIScrollView subclass (originally posted)
  138. // ------------------------------------------------
  139. class OriginalMyScrollView: UIScrollView {
  140.    
  141.     var textView: UITextView!
  142.    
  143.     var oneCharSize: CGSize = .zero
  144.    
  145.     let font = UIFont.monospacedSystemFont(ofSize: 23, weight: .regular)
  146.  
  147.     override init(frame: CGRect) {
  148.         super.init(frame: frame)
  149.         commonInit()
  150.     }
  151.     required init?(coder: NSCoder) {
  152.         super.init(coder: coder)
  153.         commonInit()
  154.     }
  155.     func commonInit() {
  156.         setupTextView()
  157.     }
  158.     func setupTextView() {
  159.        
  160.         // My text view is going to contain a maximum of 80x25 characters, so here
  161.         // I am calculating how much space that is going to take up
  162.         let line = String(repeating: "a", count: 81)
  163.         let fullText = Array(repeating: line, count: 26).joined(separator: "\n")
  164.         let unroundedSize = (fullText as NSString).size(withAttributes: [
  165.             .font: font
  166.         ])
  167.         let size = CGSize(width: ceil(unroundedSize.width), height: ceil(unroundedSize.height))
  168.  
  169.         let unroundedCharSize = ("W" as NSString).size(withAttributes: [
  170.             .font: font
  171.         ])
  172.         oneCharSize = CGSize(width: ceil(unroundedCharSize.width), height: ceil(unroundedCharSize.height))
  173.  
  174.         textView = UITextView(frame: CGRect(origin: .zero, size: size))
  175.         contentSize = size
  176.        
  177.         addSubview(textView)
  178.        
  179.         textView.spellCheckingType = .no
  180.         textView.dataDetectorTypes = []
  181.         textView.font = font
  182.        
  183.         // dummy text
  184.         textView.text = """
  185. UILabel
  186.  
  187. 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.
  188.  
  189. UIButton
  190.  
  191. Displays a plain styled button that can have a title, subtitle, image, and other appearance properties.
  192.  
  193. """
  194.        
  195.         // the text view do not need to scroll. All the scrolling is done
  196.         // by the scroll view
  197.         textView.isScrollEnabled = false
  198.  
  199.         // so we can see it
  200.         textView.backgroundColor = .yellow
  201.        
  202.     }
  203.  
  204.     override func scrollRectToVisible(_ rect: CGRect, animated: Bool) {
  205.  
  206.         if let selectedTextRange = textView.selectedTextRange {
  207.             let caretPositionRect = textView.caretRect(for: selectedTextRange.start)
  208.  
  209.             var x: CGFloat = contentOffset.x
  210.  
  211.             if caretPositionRect.minX - contentOffset.x < oneCharSize.width {
  212.                 x += (caretPositionRect.minX - contentOffset.x) - oneCharSize.width
  213.                 x = max(0, x)
  214.             } else if ((caretPositionRect.minX - contentOffset.x) - frame.width) > -oneCharSize.width {
  215.                 x = caretPositionRect.minX - frame.width
  216.                 x += oneCharSize.width
  217.                 x = min(x, contentSize.width - frame.width)
  218.             }
  219.  
  220.             contentOffset.x = x
  221.         }
  222.     }
  223.    
  224. }
  225.  
Add Comment
Please, Sign In to add comment