ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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)
            
        }

     

     

    성공

    댓글

Designed by Tistory.