관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] iOS16+ UITextView 입력 중 위로 스크롤 되는 버그 해결 방법 (UIScrollView, UIStackView, UITextView) 본문

iOS 응용 (swift)

[iOS - swift] iOS16+ UITextView 입력 중 위로 스크롤 되는 버그 해결 방법 (UIScrollView, UIStackView, UITextView)

jake-kim 2023. 11. 16. 01:27

* 업데이트 된 최신글: https://ios-development.tistory.com/1565

UITextView 입력 중 위로 스크롤 되는 현상

  • UIStackView를 사용하여 리스트 형태의 뷰를 보여줄 때 중간에 UITextView가 있다면 버그가 발생
    • 뷰형태: UIScrollView안에 UIStackView을 넣고, 이 스택뷰에 UITextView 넣어서 리스트 형태의 뷰를 만든 형태

ex) 뷰 형태

import UIKit

class ViewController: UIViewController {
    private let scrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    private let stackView = {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.translatesAutoresizingMaskIntoConstraints = false
        return stackView
    }()
    private let textView = {
        let t = UITextView()
        t.text = "long \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n input...abcdef123456789"
        t.textColor = .gray
        t.isScrollEnabled = false
        t.font = .systemFont(ofSize: 30)
        t.translatesAutoresizingMaskIntoConstraints = false
        return t
    }()
    private let button = {
        let b = UIButton()
        b.setTitle("button", for: .normal)
        b.setTitleColor(.blue, for: .normal)
        b.setTitleColor(.systemBlue, for: .highlighted)
        return b
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(scrollView)
        scrollView.addSubview(stackView)
        stackView.addArrangedSubview(textView)
        stackView.addArrangedSubview(button)
        
        NSLayoutConstraint.activate([
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
        ])
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
            stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            stackView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width)
        ])
    }
}
  • iOS16부터 위로 스크롤되는 현상이 존재
    • 스크롤을 내려서 하단에 글을 작성하다보면 스크롤이 위로 튕기는 이슈 존재

문제점

  • iOS16부터 재현되는 버그이고 이 버그의 원인을 추측해보면 문자열이 타이핑되면서 UITextView 크기가 증가하는데 iOS 내부적으로 계산오류가 발생하여 layout이 새로그려지는 버그로 추측

해결방법

  • 이 계산오류를 막기위해서 textView의 크기가 변경되는 시점에서 UIStackView, UIScrollView의 크기를 재계산해주어야함
    • UITextViewDelegate의 textViewDidChnage 메서드에서 scrollView를 즉각 계산하도록 처리
textView.delegate = self

extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        scrollView.layoutIfNeeded()
    }
}

완료)

마지막에 텍스트를 입력해도 스크롤이 위로 튕기지 않음

* 전체 코드: https://github.com/JK0369/ExiOS16TextInputDelegate

Comments