Thursday, July 13, 2023
HomeiOS Developmentios - UITextView scroll will get caught whereas utilizing Textual content Package...

ios – UITextView scroll will get caught whereas utilizing Textual content Package 2


I’m utilizing textual content package 2 in UITextView by making usingTextLayoutManager property true. I’m attempting so as to add left and proper indents in NSAttributedString to get indented textual content. When I’ve a protracted textual content and once I apply indents on paragraph fashion (NSParagraphStyle), My UITextView will get caught and I can not scroll to backside. I believe it has one thing to do with contentSize of the UITextView. I’ve tried all the pieces. It really works advantageous with textual content package 1, however I’ve to make use of textual content package 2 for its new options.
Here is my code:

UITextView

import UIKit

class MyTextView: UITextView {
    
    comfort init(usingTextLayoutManager: Bool) {
        self.init(body: .zero, textContainer: nil)
    }
    
    override init(body: CGRect, textContainer: NSTextContainer?) {
        tremendous.init(body: body, textContainer: textContainer)
        
        setUpTextView()
        setUpAttributes()
        setUpInputAccessoryView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }
    
    func setUpTextView() {
        alwaysBounceVertical = true
        keyboardDismissMode = .interactiveWithAccessory
        backgroundColor = .white
    }
    
    func setUpAttributes() {
        let font = UIFont.systemFont(ofSize: 24, weight: .semibold)
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = font.pointSize * 0.15
        
        typingAttributes = [
            .font: font,
            .paragraphStyle: paragraphStyle
        ]
        
        let string = "Once you strive your greatest, however you do not succeednWhen you get what you need, however not what you neednWhen you are feeling so drained, however you'll be able to't sleepnStuck in reversenAnd the tears come streaming down your facenWhen you lose one thing you'll be able to't replacenWhen you like somebody, nevertheless it goes to wastenCould or not it's worse?nLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair younAnd excessive up above, or down belownWhen you are too in like to let it gonBut should you by no means strive, you may by no means knownJust what you are worthnLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair younTears stream down your facenWhen you lose one thing you can not replacenTears stream down your face, and InTears stream down your facenI promise you I'll be taught from my mistakesnTears stream down your face, and InLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair younWhen you strive your greatest, however you do not succeednWhen you get what you need, however not what you neednWhen you are feeling so drained, however you'll be able to't sleepnStuck in reversenAnd the tears come streaming down your facenWhen you lose one thing you'll be able to't replacenWhen you like somebody, nevertheless it goes to wastenCould or not it's worse?nLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair younAnd excessive up above, or down belownWhen you are too in like to let it gonBut should you by no means strive, you may by no means knownJust what you are worthnLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair younTears stream down your facenWhen you lose one thing you can not replacenTears stream down your face, and InTears stream down your facenI promise you I'll be taught from my mistakesnTears stream down your face, and InLights will information you homenAnd ignite your bonesnAnd I'll attempt to repair you"
        
        let attributedString = NSMutableAttributedString(
            string: string,
            attributes: [
                .font: font,
                .paragraphStyle: paragraphStyle
            ]
        )
        
        textStorage.setAttributedString(attributedString)
    }
    
    func indentLeft() {
        let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
        let paragraphRange = mutableAttributedText.mutableString.paragraphRange(for: selectedRange)
        
        textStorage.enumerateAttribute(.paragraphStyle, in: paragraphRange) { attribute, vary, _ in
            if let paragraphStyle = attribute as? NSParagraphStyle {
                let newParagraphStyle = paragraphStyle.mutableCopy() as! NSMutableParagraphStyle
                if newParagraphStyle.firstLineHeadIndent > 0 {
                    newParagraphStyle.firstLineHeadIndent -= 40
                    newParagraphStyle.headIndent -= 40
                } else {
                    newParagraphStyle.firstLineHeadIndent = 0
                    newParagraphStyle.headIndent = 0
                }
                textStorage.addAttribute(.paragraphStyle, worth: newParagraphStyle, vary: vary)
            }
        }
    }
    
    func indentRight() {
        let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
        let paragraphRange = mutableAttributedText.mutableString.paragraphRange(for: selectedRange)
        
        textStorage.enumerateAttribute(.paragraphStyle, in: paragraphRange) { attribute, vary, _ in
            if let paragraphStyle = attribute as? NSParagraphStyle {
                let newParagraphStyle = paragraphStyle.mutableCopy() as! NSMutableParagraphStyle
                if newParagraphStyle.firstLineHeadIndent < 160 {
                    newParagraphStyle.firstLineHeadIndent += 40
                    newParagraphStyle.headIndent += 40
                } else {
                    newParagraphStyle.firstLineHeadIndent = 0
                    newParagraphStyle.headIndent = 0
                }
                textStorage.addAttribute(.paragraphStyle, worth: newParagraphStyle, vary: vary)
            }
        }
    }
    
    func setUpInputAccessoryView() {
        let view = AccessoryView(body: .init(origin: .zero, dimension: .init(width: .zero, peak: 50)))
        view.textView = self
        inputAccessoryView = view
    }
}

ViewController

class ViewController: UIViewController {
    
    var textView: MyTextView!
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        view.backgroundColor = .white
        setUpTextView()
    }
    
    func setUpTextView() {
        textView = MyTextView()
        textView.layer.borderColor = UIColor.black.cgColor
        textView.layer.borderWidth = 2
        view.addSubview(textView)
        setUpConstraints()
        let _ = textView.becomeFirstResponder()
    }
    
    func setUpConstraints() {
        textView.translatesAutoresizingMaskIntoConstraints = false
        
        [   textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ].forEach {
            $0.isActive = true
        }
    }
}

Accent view for textView

class AccessoryView: UIView {
    
    weak var textView: MyTextView?
    
    let indentLeft: UIButton = {
        let button = UIButton(kind: .system)
        button.setImage(UIImage(systemName: "lessthan"), for: .regular)
        return button
    }()
    
    let indentRight: UIButton = {
        let button = UIButton(kind: .system)
        button.setImage(UIImage(systemName: "greaterthan"), for: .regular)
        return button
    }()
    
    override init(body: CGRect) {
        tremendous.init(body: body)
        
        backgroundColor = .white
        layer.borderColor = UIColor.black.cgColor
        layer.borderWidth = 2
        
        addSubview(indentLeft)
        indentLeft.translatesAutoresizingMaskIntoConstraints = false
        indentLeft.topAnchor.constraint(equalTo: topAnchor).isActive = true
        indentLeft.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        indentLeft.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        indentLeft.widthAnchor.constraint(equalToConstant: 55).isActive = true
        indentLeft.addTarget(self, motion: #selector(handleIndentLeft), for: .touchUpInside)
        
        addSubview(indentRight)
        indentRight.translatesAutoresizingMaskIntoConstraints = false
        indentRight.topAnchor.constraint(equalTo: topAnchor).isActive = true
        indentRight.leadingAnchor.constraint(equalTo: indentLeft.trailingAnchor).isActive = true
        indentRight.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        indentRight.widthAnchor.constraint(equalToConstant: 55).isActive = true
        indentRight.addTarget(self, motion: #selector(handleIndentRight), for: .touchUpInside)
    }
    
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }
    
    @objc func handleIndentLeft(button: UIButton) {
        guard let textView = textView else {
            return
        }
        
        textView.indentLeft()
    }
    
    @objc func handleIndentRight(button: UIButton) {
        guard let textView = textView else {
            return
        }
        
        textView.indentRight()
    }
}

How recreate subject:

  1. Run it in your telephone.
  2. Choose all textual content.
  3. press proper indent button 2-3 occasions
  4. then scroll to prime and once more scroll to backside.

Have you learnt why is it taking place and the way can I resolve it?



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments