훌이
후리스콜링개발
훌이

블로그 메뉴

  • 왈 (iOS APP)
  • Github
전체 방문자
오늘
어제
  • 전체 (171)
    • ⭐️ 개발 (140)
      • JAVA (4)
      • Web (5)
      • iOS & Swift (94)
      • iOS Concurrency (4)
      • Rx (18)
      • Git (6)
      • WWDC (1)
      • Code Refactor (3)
      • Server (1)
    • ⭐️ Computer Science (22)
      • 운영체제 (10)
      • 네트워크 (5)
      • PS (7)
    • 경제시사상식 (8)
    • 기타 등등 (0)

인기 글

최근 글

05-20 03:12

티스토리

hELLO · Designed By 정상우.
훌이

후리스콜링개발

[iOS] TextView - 플레이스홀더, 패딩, 글자 수 제한, 커서, 키보드 dismiss
⭐️ 개발/iOS & Swift

[iOS] TextView - 플레이스홀더, 패딩, 글자 수 제한, 커서, 키보드 dismiss

2021. 7. 22. 04:26
728x90
반응형

📦 TextView - 플레이스홀더, 패딩, 글자 수 제한, 커서 색상, 키보드 dismiss

프로젝트를 하면서 TextView를 사용해 다양한 기능을 구현하게 되어 정리를 해봅니다!

SnapKit과 Then 라이브러리를 사용하였습니다!

 

<전체 코드는 아래 있고,

색상은 프로젝트하면서 extension으로 추가해준 색상을 사용해서 따로 네이밍된 상태입니다.>

Github - https://github.com/heerucan/iOS-Practice/tree/main/TextView%20Practice

 

우선, textView를 사용하려면 UITextViewDelegate 프로토콜을 해당 뷰컨에 채택해주고 위임처리를 해주어야 합니다.


1. Placeholder

-> TextView는 TextField와 다르게 기본적으로 placeholder를 제공해주지 않기 때문에

textView.text를 통해 placeholder인 척 기능을 구현해봤습니다.

 

1️⃣ 텍스트뷰를 수정하기 시작할 때 (textViewDidBeginEditing)

유저가 텍스트를 입력하기 시작하면 글자색이 흰색으로 변경되어야 합니다.

 

 

2️⃣ 텍스트뷰 수정을 끝냈을 때 == 키보드를 내릴 때 (textViewDidEndEditing)

만약, 수정을 끝낼 때에 유저가 아무 것도 입력하지 않았을 때는 placeholder를 보여줘야 합니다.또한, 입력이 완료된 상태는 keyboard가 내려간 상태와 같다고 인지할 수 있도록 VC 내에 touchesBegan 함수를 오버라이드 해주었습니다.

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true) /// 화면을 누르면 키보드 내려가게 하는 것
    }

 

* 한 가지 걱정되는 부분은 만약 유저가 placeholder로 지정해 놓은 글자와 똑같이 textView에 입력할 경우에는 어쩌나...라는... 생각이 들었고.. 애플이 얼른 하루 빨리 textView에도 placeholder 기능을 내주길 바라며....;;;

 

let placeholder = "(예 : 오늘 아침에 일어나서 중랑천 2.5km 뛰었음)"
extension ViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        /// 플레이스홀더
        if textView.text.isEmpty {
            activityTextView.textColor = .gray200
            activityTextView.text = placeholder
        } else if textView.text == placeholder {
            activityTextView.textColor = .white
            activityTextView.text = nil
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        /// 플레이스홀더
        if textView.text.isEmpty {
            activityTextView.textColor = .gray200
            activityTextView.text = placeholder
        }
    }
}

 

 

‼️‼️

-> 여기서 하나 주의할 점은 만약 유저가 띄어쓰기를 입력할 경우입니다!

공백 또는 줄바꿈을 입력할 경우에도 placeholder를 적용시키려면 문자열의 앞뒤 공백과 줄바꿈을 제거해주는

trimmingCharacters(in: .whitespacesAndNewlines)를 통해 가능합니다.

extension AddActionVC: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        /// 플레이스 홀더
        if textView.text == placholder {
            textView.text = nil
            textView.textColor = .white
        } else if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            textView.text = placholder
            textView.textColor = .gray200
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            textView.text = placholder
            textView.textColor = .gray200
        }
    }
}

 

2. 패딩

-> textView 내에서 커서를 입력하면 왼쪽 패딩 값이 없는 걸 볼 수 있는데

패딩 값을 주려면 textContainerInset를 사용해서 textView 내부의 상하좌우 inset 값을 설정해 줄 수 있습니다.

let activityTextView = UITextView().then {
    $0.textContainerInset = UIEdgeInsets(top: 18, left: 18, bottom: 18, right: 18)
}

 

3. 글자 수 제한

-> UITextViewDelegate 안 textViewDidChange 함수 안에 텍스트뷰의 텍스트 개수가 150자를 넘어갈 경우

deleteBackward()를 통해서 커서 바로 전 문자를 삭제하도록 해줍니다!

func textViewDidChange(_ textView: UITextView) {
    if activityTextView.text.count > 150 {
       activityTextView.deleteBackward()
    }
}

 

 

‼️‼️

-> 좀 더 심화로,,,

현재 몇 글자를 작성했는지 표시해주는 ui를 구현해 보았습니다!

activityTextView.text.count를 통해 현재 텍스트뷰의 텍스트 개수를 label.text로 바로 반영해줬습니다.

 

NSMutableAttributedString 을 통해서 문자열의 특정 부분의 색상을 변경시켜줬습니다.

    func textViewDidChange(_ textView: UITextView) {
        /// 글자 수 제한
        if activityTextView.text.count > 150 {
            activityTextView.deleteBackward()
        }
        
        /// 아래 글자 수 표시되게 하기
        letterNumLabel.text = "\(activityTextView.text.count)/150"
        
        /// 글자 수 부분 색상 변경
        let attributedString = NSMutableAttributedString(string: "\(activityTextView.text.count)/150")
        attributedString.addAttribute(.foregroundColor, value: UIColor.pink100, range: ("\(activityTextView.text.count)/150" as NSString).range(of:"\(activityTextView.text.count)"))
        letterNumLabel.attributedText = attributedString
    }

 

‼️‼️ 

그리고 공백이나 줄바꿈을 입력할 때 글자 수 표시를 " 0/150 "으로 표시해주기 위해서는 

textView.text가 공백일 경우에 해당 조건을 넣어주면 됩니다.

    func textViewDidEndEditing(_ textView: UITextView) {
        /// 텍스트뷰 입력 완료시 테두리 없애기
        activityTextView.layer.borderWidth = 0
        
        /// 플레이스홀더
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || textView.text == placeholder {
            activityTextView.textColor = .gray200
            activityTextView.text = placeholder
            letterNumLabel.textColor = .gray200 /// 텍스트 개수가 0일 경우에는 글자 수 표시 색상이 모두 gray 색이게 설정
            letterNumLabel.text = "0/150"
        }
    }

 

 

4. 커서 색깔

-> tintColor를 설정해주면 됩니다

let activityTextView = UITextView().then {
    $0.tintColor = .pink100
}

구 현 영 상 ~ 

 

전 체 코 드 ~ 

//
//  ViewController.swift
//  TextView Practice
//
//  Created by Thisisme Hi on 2021/07/20.
//

import UIKit

import Then
import SnapKit

class ViewController: UIViewController {
    // MARK: - Properties
    let placeholder = "(예 : 오늘 아침에 일어나서 중랑천 2.5km 뛰었음)"
    
    let activityTextView = UITextView().then {
        $0.font = .systemFont(ofSize: 14)
        $0.layer.cornerRadius = 18
        $0.backgroundColor = .black200
        $0.tintColor = .pink100
        $0.textContainerInset = UIEdgeInsets(top: 18, left: 18, bottom: 18, right: 18)
    }
    
    let letterNumLabel = UILabel().then {
        $0.text = "0/150"
        $0.font = .systemFont(ofSize: 16)
        $0.textColor = .gray200
        $0.textAlignment = .right
    }
    
    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        configUI()
        setupAutoLayout()
        setupTextView()
    }
    
    // MARK: - Custom Method
    func configUI() {
        view.backgroundColor = .black
    }
    
    func setupAutoLayout() {
        view.addSubview(activityTextView)
        view.addSubview(letterNumLabel)
        
        activityTextView.snp.makeConstraints { make in
            make.top.equalTo(200)
            make.centerX.equalToSuperview()
            make.height.equalTo(190)
            make.width.equalTo(319)
        }
        
        letterNumLabel.snp.makeConstraints { make in
            make.top.equalTo(activityTextView.snp.bottom).offset(6)
            make.trailing.equalToSuperview().inset(28)
        }
    }
    
    func setupTextView() {
        activityTextView.delegate = self
        activityTextView.text = placeholder /// 초반 placeholder 생성
        activityTextView.textColor = .gray200 /// 초반 placeholder 색상 설정
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true) /// 화면을 누르면 키보드 내려가게 하는 것
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        /// 텍스트뷰 입력 시 테두리 생기게 하기
        activityTextView.layer.borderWidth = 1
        activityTextView.layer.borderColor = UIColor.pink100.cgColor
        
        /// 플레이스홀더
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            activityTextView.textColor = .gray200
            activityTextView.text = placeholder
        } else if textView.text == placeholder {
            activityTextView.textColor = .white
            activityTextView.text = nil
        }
    }
    
    func textViewDidChange(_ textView: UITextView) {
        /// 글자 수 제한
        if activityTextView.text.count > 150 {
            activityTextView.deleteBackward()
        }
        
        /// 아래 글자 수 표시되게 하기
        letterNumLabel.text = "\(activityTextView.text.count)/150"
        
        /// 글자 수 부분 색상 변경
        let attributedString = NSMutableAttributedString(string: "\(activityTextView.text.count)/150")
        attributedString.addAttribute(.foregroundColor, value: UIColor.pink100, range: ("\(activityTextView.text.count)/150" as NSString).range(of:"\(activityTextView.text.count)"))
        letterNumLabel.attributedText = attributedString
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        /// 텍스트뷰 입력 완료시 테두리 없애기
        activityTextView.layer.borderWidth = 0
        
        /// 플레이스홀더
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || textView.text == placeholder {
            activityTextView.textColor = .gray200
            activityTextView.text = placeholder
            letterNumLabel.textColor = .gray200 /// 텍스트 개수가 0일 경우에는 글자 수 표시 색상이 모두 gray 색이게 설정
            letterNumLabel.text = "0/150"
        }
    }
}

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글

[iOS] NotificationCenter?  (0) 2021.07.29
[iOS] Moya가 모야? - Moya로 Get 통신하기  (10) 2021.07.25
[iOS] Alamofire Multipart/formdata를 통한 이미지 서버 통신  (3) 2021.07.19
[iOS] DateFormatter  (2) 2021.06.24
[iOS] Expandable TableView Cell 만들기  (6) 2021.06.16
    '⭐️ 개발/iOS & Swift' 카테고리의 다른 글
    • [iOS] NotificationCenter?
    • [iOS] Moya가 모야? - Moya로 Get 통신하기
    • [iOS] Alamofire Multipart/formdata를 통한 이미지 서버 통신
    • [iOS] DateFormatter
    훌이
    훌이

    티스토리툴바