-
iOS) Dynamic TextView의 Underline - TextView에 밑줄 추가하기iOS 2021. 3. 5. 10:56
textField에 under line을 생성하는 예제는 많다.
dynamic textView를 생성하는 예제도 많다.
둘을 합쳐보자.
우선 textView에 under line을 추가하는 코드이다.
func underLine() { let border = CALayer() border.frame = CGRect(x: 0, y: self.frame.size.height-1, width: self.frame.width, height: 1) border.borderWidth = 1 border.backgroundColor = UIColor.black.cgColor self.layer.addSublayer(border) }
간단하게 layer를 textView의 frame에 맞추어 만들어 sublayer로 추가 하는것이다.
참고로 textView의 frame을 얻기 위해 viewDidLoad() 가 아닌 viewWillLayoutSubviews()에서 추가해 주거나, textView를 추가 한 후 layoutifNeeded()를 통해 view의 layout을 업데이트 해준 후 추가해 주어야 한다.
textView의 크기를 text에 맞추어 갱신하는 코드이다.
func automaticallySizeToFit(superFrame: CGSize) { let initalSize = CGSize(width: superFrame.width, height: 1000) let estimateSize = dynamicTextView.sizeThatFits(initalSize) dynamicTextView.constraints.forEach { (constraint) in if constraint.firstAttribute == .height { constraint.constant = estimateSize.height } } }
sizeTahtFits() 함수는 적용되는 view에 대해 최적화 된 size를 리턴 해준다.
그 후 textView의 height constraint를 찾아 최적화 된 size의 height로 변환 해준다.
자 그럼 dynamicTextView에 layer를 추가 해서 밑줄이 있는 dynamicTextView를 만들어보자.
엥
밑줄이 변화되는 view의 크기에 따라서 움직이지 않는다.
layer는 view가 아니다. layer를 생성시 autoLayout이 아닌 '값'으로 지정해야 한다.
따라서 밑줄은 생성시 frame 값 그대로 남아있게 된다.
textView의 bottom에 밑줄이 고정되는 형태로 만들어보자.
textViewDelegate를 통해 view 크기가 업데이트 될때 layer도 같이 업데이트 해보기
layer를 global property로 생성하여 textViewDidChange(_ textView: UITextView)에서 업데이트 해줘보자.
물론 객체지향에 어긋나지만 일단 해보자.
func automaticallySizeToFit(superFrame: CGSize) { let initalSize = CGSize(width: 350, height: 1000) let estimateSize = dynamicTextView.sizeThatFits(initalSize) // 요기서 밑줄 업데이트 border.frame = CGRect(x: 0, y: estimateSize.height - 3, width: dynamicTextView.frame.width, height: 1) dynamicTextView.constraints.forEach { (constraint) in if constraint.firstAttribute == .height { constraint.constant = estimateSize.height } } }
실패~
우리에겐 autoLayout이 필요하다.
CALayer가 아닌 UIView의 형태로 underline 만들기
view형태의 underline을 만들어 autoLayout을 적용시킨다면 되지 않을까...
func underLine() { let underLineView = UIView() self.addSubview(underLineView) underLineView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ underLineView.bottomAnchor.constraint(equalTo: self.bottomAnchor), underLineView.centerXAnchor.constraint(equalTo: self.centerXAnchor), underLineView.widthAnchor.constraint(equalToConstant: 100), underLineView.heightAnchor.constraint(equalToConstant: 1) ]) underLineView.layer.borderWidth = 1 underLineView.layer.backgroundColor = UIColor.black.cgColor }
UITextView에 extension을 통해 추가 해주었다.
결과는...?
읭?..
아마 textView의 scrollView의 재사용 그 머시기 때문에 topAnchor 바로 위에 bottom Anchor가 잡히지 않았나 싶다..
최후의 수단 StackView로 감싸기
마지막 방법은 textView와 UnderLine 형태의 View를 stackView로 감싸는 것이다.
var containerStackView: UIStackView = { var stackView = UIStackView() stackView.backgroundColor = .blue stackView.axis = .vertical stackView.alignment = .fill stackView.distribution = .fill stackView.spacing = 0 return stackView }() var textView: UITextView = { var textView = UITextView() textView.text = "dynamic textView with underline" textView.font = UIFont.boldSystemFont(ofSize: 20) return textView }() var underLine: UIView = { var view = UIView() view.layer.borderWidth = 1 view.layer.borderColor = UIColor.black.cgColor return view }() override func viewDidLoad() { super.viewDidLoad() textView.delegate = self view.addSubview(containerStackView) containerStackView.addArrangedSubview(textView) containerStackView.addArrangedSubview(underLine) containerStackView.translatesAutoresizingMaskIntoConstraints = false textView.translatesAutoresizingMaskIntoConstraints = false underLine.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ containerStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), containerStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), containerStackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9), textView.widthAnchor.constraint(equalTo: containerStackView.widthAnchor), textView.heightAnchor.constraint(equalToConstant: 100), underLine.widthAnchor.constraint(equalTo: containerStackView.widthAnchor), underLine.heightAnchor.constraint(equalToConstant: 1) ]) view.layoutIfNeeded() textViewDidChange(textView) }
성공
'iOS' 카테고리의 다른 글
WWDC) Animation hitch와 render loop (0) 2022.04.05 Cocoapods) custom 라이브러리에 이미지 파일 embedded 하기 (0) 2021.08.04 iOS) CoreData - perform 메소드 (0) 2021.01.31 iOS) Core Data (4) - Entity Hierarchy and Relationship (0) 2021.01.31 iOS) Core Data (3) - CRUD (0) 2021.01.27