관리 메뉴

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

[iOS - swift] TextView placeholder 적용 방법 본문

iOS 응용 (swift)

[iOS - swift] TextView placeholder 적용 방법

jake-kim 2021. 9. 8. 23:17

placeholder 적용

placeholder: "텍스트를 입력하세요"
text가 비어있는 경우 placeHolder 적용

textView 초기화

  • text를 placeHolder 문자열, color를 placeHolder 색상으로 변경
  • delegate 설정
// ViewController.swift

let textViewPlaceHolder = "텍스트를 입력하세요"
lazy var textView: UITextView = {
    let view = UITextView()
    view.layer.borderWidth = 1.0
    view.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.7).cgColor
    view.textContainerInset = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
    view.font = .systemFont(ofSize: 18)
    view.text = textViewPlaceHolder
    view.textColor = .lightGray
    view.delegate = self // <-

    return view
}()

delegate를 사용하여 placeholder 구현

  • textView에 focus를 얻는 경우 발생 delegate: textViewDidBeginEditing(_ textView: UITextView)

  • textView에 focus를 잃는 경우 발생 delegate: textViewDidEndEditing(_ textView: UITextView)

  • focus를 얻는 경우: text가 placeholder로 그대로 남아 있다면, 입력을 준비하기 위해서 text를 nil, color를 input색상으로 변경
func textViewDidBeginEditing(_ textView: UITextView) {
    if textView.text == textViewPlaceHolder {
        textView.text = nil
        textView.textColor = .black
    }
}
  • focus를 읽는 경우: text가 비어있다면 text를 placeholder로 하고 color도 placeholder 색상으로 변경
func textViewDidEndEditing(_ textView: UITextView) {
    if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
        textView.text = textViewPlaceHolder
        textView.textColor = .lightGray
    }
}

* 전체 코드

import UIKit

class ViewController: UIViewController {

    let textViewPlaceHolder = "텍스트를 입력하세요"

    lazy var textView: UITextView = {
        let view = UITextView()
        view.layer.borderWidth = 1.0
        view.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.7).cgColor
        view.textContainerInset = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
        view.font = .systemFont(ofSize: 18)
        view.text = textViewPlaceHolder
        view.textColor = .lightGray
        view.delegate = self

        return view
    }()

    lazy var remainCountLabel: UILabel = {
        let label = UILabel()
        label.textColor = .black
        label.text = "0/700"
        label.font = .systemFont(ofSize: 30)
        label.textColor = .lightGray
        label.textAlignment = .center

        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textView)
        view.addSubview(remainCountLabel)

        textView.translatesAutoresizingMaskIntoConstraints = false
        remainCountLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            textView.heightAnchor.constraint(equalToConstant: 300),

            remainCountLabel.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 12),
            remainCountLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapTextView(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    @objc
    private func didTapTextView(_ sender: Any) {
        view.endEditing(true)
    }

    private func updateCountLabel(characterCount: Int) {
        remainCountLabel.text = "\(characterCount)/500"
        remainCountLabel.asColor(targetString: "\(characterCount)", color: characterCount == 0 ? .lightGray : .blue)
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == textViewPlaceHolder {
            textView.text = nil
            textView.textColor = .black
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            textView.text = textViewPlaceHolder
            textView.textColor = .lightGray
            updateCountLabel(characterCount: 0)
        }
    }

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let inputString = text.trimmingCharacters(in: .whitespacesAndNewlines)
        guard let oldString = textView.text, let newRange = Range(range, in: oldString) else { return true }
        let newString = oldString.replacingCharacters(in: newRange, with: inputString).trimmingCharacters(in: .whitespacesAndNewlines)

        let characterCount = newString.count
        guard characterCount <= 700 else { return false }
        updateCountLabel(characterCount: characterCount)

        return true
    }
}

extension UILabel {
    func asColor(targetString: String, color: UIColor?) {
        let fullText = text ?? ""
        let range = (fullText as NSString).range(of: targetString)
        let attributedString = NSMutableAttributedString(string: fullText)
        attributedString.addAttribute(.foregroundColor, value: color as Any, range: range)
        attributedText = attributedString
    }
}

* 참고

- textViewDidBeginEditing(_ textView: UITextView):

https://developer.apple.com/documentation/uikit/uitextviewdelegate/1618610-textviewdidbeginediting

- textViewDidEndEditing(_ textView: UITextView): https://developer.apple.com/documentation/uikit/uitextviewdelegate/1618628-textviewdidendediting

Comments