Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 클린 코드
- RxCocoa
- Protocol
- 스위프트
- combine
- collectionview
- HIG
- map
- 리펙토링
- swiftUI
- MVVM
- ribs
- 애니메이션
- Xcode
- Human interface guide
- tableView
- Refactoring
- ios
- uitableview
- UICollectionView
- swift documentation
- SWIFT
- 리펙터링
- Observable
- 리팩토링
- uiscrollview
- UITextView
- rxswift
- clean architecture
- Clean Code
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] PlaceholderTextView 구현 방법 (UITextView안에 placeholder 구현 방법) 본문
UI 컴포넌트 (swift)
[iOS - swift] PlaceholderTextView 구현 방법 (UITextView안에 placeholder 구현 방법)
jake-kim 2023. 7. 14. 01:36
PlaceholderTextView 구현 아이디어
- UITextView에는 기본적으로 가지고 있는 placeholder 속성이 없기 때문에 커스텀이 필요
- 잘못 구현하는 케이스
- 1) UITextView하나만 가지고 텍스트 입력이 시작될 때 textColor와 text를 순간적으로 변경 -> 포커스 위치가 글씨 맨 오른쪽으로 가거나, 포커스 되는 순간 placeholder 값을 지워함 (placeholder는 한 글자 이상 입력될때 없어지도록 구현 불가(
- 2) UILabel을 두어 UITextView위에 얹져서 구현 -> 깜빡거리는 포커스보다 UILabel이 위에 있기 때문에 깜빡거리는 포커스가 안보이는 현상 발생
- UITextView안에 placeholder 전용으로 사용하는 UITextView를 별도로 두어서 구현
- UITextView안에 UITextView를 두고 backgroundColor를 clear로 설정하면 text글씨가 있는 동시에 깜빡거리는 포커스가 이 위에 위치하므로 원하는 형태의 UI 구현이 가능
구현
- UITextView안에 UITextView가 있어야 하므로 UITextView를 상속받는 뷰 선언
import UIKit
final class PlaceholderTextView: UITextView {
}
- 매직넘버를 방지하기 위해 필요한 상수값 선언
private enum Const {
static let backgroundColor = UIColor.lightGray.withAlphaComponent(0.3)
static let cornerRadius = 14.0
static let containerInset = UIEdgeInsets(top: 30, left: 24, bottom: 30, right: 24)
static let placeholderColor = UIColor(red: 0, green: 0, blue: 0.098, alpha: 0.22)
}
- placeholder 전용으로 사용할 UITextView 선언
- 중요한점: 해당 뷰는 보여지기만 하고 인터렉션이 없어야 하므로, isUserInteractionEnabled와 isAccessibilityElement를 모두 비활성해야함
private let placeholderTextView: UITextView = {
let view = UITextView()
view.backgroundColor = .clear
view.textColor = Const.placeholderColor
view.isUserInteractionEnabled = false
view.isAccessibilityElement = false
return view
}()
- 뷰들의 초기값 설정
init() {
super.init(frame: .zero, textContainer: nil)
setupUI()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("\(#function) has not been implemented")
}
func setupUI() {
delegate = self
backgroundColor = Const.backgroundColor
layer.cornerRadius = Const.cornerRadius
clipsToBounds = true
textContainerInset = Const.containerInset
contentInset = .zero
addSubview(placeholderTextView)
placeholderTextView.textContainerInset = Const.containerInset
placeholderTextView.contentInset = contentInset
}
- 외부에서 세팅할 수 있는 값 선언
var placeholderText: String? {
didSet {
placeholderTextView.text = placeholderText
updatePlaceholderTextView() // 아래에서 계속 구현
}
}
- 위에서 등장한 updatePlaceholderTextView()는 핵심 부분
- 텍스트가 추가되거나, 변경되거나 할 때 해당 메소드가 호출되어, palceholderTextView의 isHidden 필드와 frame값을 재정의해주는 뷰
- frame값을 재정의 해주는것이 핵심 (placeholderTextView를 품고 있는 뷰의 크기는 UITextView내부에서 자동으로 크기를 늘려주거나 줄여줄기 때문에, 내부적으로 선언한 placeholderTextView도 이와 동일한 크기를 유지하기위해 frame값 업데이트가 계속 필요)
func updatePlaceholderTextView() {
placeholderTextView.isHidden = !text.isEmpty
accessibilityValue = text.isEmpty ? placeholderText ?? "" : text
placeholderTextView.textContainer.exclusionPaths = textContainer.exclusionPaths
placeholderTextView.textContainer.lineFragmentPadding = textContainer.lineFragmentPadding
placeholderTextView.frame = bounds
}
(해당 메소드를 호출하는 부분 3곳)
final class PlaceholderTextView: UITextView {
...
var placeholderText: String? {
didSet {
placeholderTextView.text = placeholderText
updatePlaceholderTextView() // <-
}
}
override func layoutSubviews() {
super.layoutSubviews()
updatePlaceholderTextView() // <-
}
}
extension PlaceholderTextView: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
updatePlaceholderTextView() // <-
}
}
사용하는 곳
import UIKit
class ViewController: UIViewController {
private let placeholderTextView = PlaceholderTextView()
override func viewDidLoad() {
super.viewDidLoad()
placeholderTextView.placeholderText = "값을 입력해주세요"
view.addSubview(placeholderTextView)
placeholderTextView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
placeholderTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
placeholderTextView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
placeholderTextView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
placeholderTextView.heightAnchor.constraint(equalToConstant: 200),
])
}
}
(완성)
* 전체 코드: https://github.com/JK0369/ExPlaceholderTextView.git
'UI 컴포넌트 (swift)' 카테고리의 다른 글
Comments