-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
460 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// | ||
// TextViewController.swift | ||
// Handy | ||
// | ||
// Created by 정민지 on 11/18/24. | ||
// | ||
|
||
import UIKit | ||
import SnapKit | ||
|
||
import Handy | ||
|
||
final class TextViewController: BaseViewController { | ||
|
||
private let defaultTextView: HandyTextView = { | ||
let textView = HandyTextView() | ||
textView.placeholder = "Input text" | ||
textView.helperLabelText = "Helper text" | ||
textView.placeholderColor = .lightGray | ||
textView.minHeight = 187 | ||
textView.maxHeight = 187 | ||
|
||
return textView | ||
}() | ||
|
||
|
||
private let errorTextView: HandyTextView = { | ||
let textView = HandyTextView() | ||
textView.placeholder = "Input text" | ||
textView.helperLabelText = "Helper text" | ||
textView.placeholderColor = .lightGray | ||
textView.isNegative = true | ||
textView.maxHeight = 80 | ||
|
||
return textView | ||
}() | ||
|
||
private let disabledTextView: HandyTextView = { | ||
let textView = HandyTextView() | ||
textView.placeholder = "Input text" | ||
textView.helperLabelText = "Helper text" | ||
textView.placeholderColor = .lightGray | ||
textView.isDisabled = true | ||
textView.maxHeight = 187 | ||
|
||
return textView | ||
}() | ||
|
||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
setViewLayouts() | ||
} | ||
|
||
override func setViewHierarchies() { | ||
[ | ||
defaultTextView, errorTextView, disabledTextView | ||
].forEach { | ||
view.addSubview($0) | ||
} | ||
} | ||
|
||
override func setViewLayouts() { | ||
defaultTextView.snp.makeConstraints { | ||
$0.top.equalToSuperview().offset(100) | ||
$0.horizontalEdges.equalToSuperview().inset(20) | ||
} | ||
errorTextView.snp.makeConstraints { | ||
$0.top.equalTo(defaultTextView.snp.bottom).offset(20) | ||
$0.horizontalEdges.equalToSuperview().inset(20) | ||
} | ||
disabledTextView.snp.makeConstraints { | ||
$0.top.equalTo(errorTextView.snp.bottom).offset(20) | ||
$0.horizontalEdges.equalToSuperview().inset(20) | ||
} | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
Handy/Handy/Source/Atom/HandyTextView/HandyBaseTextView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
// | ||
// HandyBaseTextView.swift | ||
// Handy | ||
// | ||
// Created by 정민지 on 11/18/24. | ||
// | ||
|
||
import UIKit | ||
import SnapKit | ||
|
||
public class HandyBaseTextView: UITextView { | ||
// MARK: - 외부에서 지정할 수 있는 속성 | ||
|
||
/** | ||
텍스트 뷰를 비활성화 시킬 때 사용합니다. | ||
*/ | ||
@Invalidating(.layout) public var isDisabled: Bool = false { | ||
didSet { updateState() } | ||
} | ||
|
||
/** | ||
텍스트 필드의 오류 상태를 나타낼 때 사용합니다. | ||
*/ | ||
@Invalidating(.layout) public var isNegative: Bool = false { | ||
didSet { updateState() } | ||
} | ||
|
||
/** | ||
텍스트 뷰의 최소 높이를 설정할 때 사용합니다. | ||
*/ | ||
@Invalidating(.layout) public var minHeight: CGFloat? = 48 | ||
|
||
/** | ||
텍스트 뷰의 최대 높이를 설정할 때 사용합니다. | ||
*/ | ||
@Invalidating(.layout) public var maxHeight: CGFloat? = nil | ||
|
||
/** | ||
텍스트 뷰의 플레이스홀더를 설정할 때 사용합니다. | ||
*/ | ||
public var placeholder: String? { | ||
didSet { setupPlaceholder() } | ||
} | ||
|
||
/** | ||
플레이스홀더 텍스트 색상을 설정할 때 사용합니다. | ||
*/ | ||
public var placeholderColor: UIColor = HandySemantic.textBasicTertiary { | ||
didSet { | ||
placeholderLabel?.textColor = placeholderColor | ||
} | ||
} | ||
|
||
/** | ||
플레이스홀더 텍스트를 설정할 때 사용합니다. | ||
*/ | ||
private var placeholderLabel: UILabel? | ||
|
||
// MARK: - 메소드 | ||
|
||
public init() { | ||
super.init(frame: .zero, textContainer: nil) | ||
setupView() | ||
} | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
deinit { | ||
NotificationCenter.default.removeObserver(self) | ||
} | ||
|
||
private func setupView() { | ||
self.delegate = self | ||
self.font = HandyFont.B3Rg14 | ||
self.backgroundColor = HandySemantic.bgBasicLight | ||
self.isScrollEnabled = false | ||
self.layer.cornerRadius = HandySemantic.radiusM | ||
self.layer.borderWidth = 1 | ||
self.layer.borderColor = HandySemantic.bgBasicLight.cgColor | ||
self.textContainer.lineFragmentPadding = 0 | ||
self.textContainerInset = UIEdgeInsets( | ||
top: HandyTextViewConstants.Dimension.textContainerInset, | ||
left: HandyTextViewConstants.Dimension.textContainerInset, | ||
bottom: HandyTextViewConstants.Dimension.textContainerInset, | ||
right: HandyTextViewConstants.Dimension.textContainerInset | ||
) | ||
} | ||
|
||
private func setupPlaceholder() { | ||
if placeholderLabel == nil { | ||
placeholderLabel = UILabel() | ||
placeholderLabel?.textColor = placeholderColor | ||
placeholderLabel?.font = self.font | ||
placeholderLabel?.numberOfLines = 0 | ||
placeholderLabel?.text = placeholder | ||
guard let label = placeholderLabel else { return } | ||
self.addSubview(label) | ||
|
||
label.snp.makeConstraints { | ||
$0.edges.equalToSuperview().inset(textContainerInset) | ||
} | ||
|
||
NotificationCenter.default.addObserver(self, | ||
selector: #selector(textDidChange), | ||
name: UITextView.textDidChangeNotification, | ||
object: nil) | ||
} else { | ||
placeholderLabel?.text = placeholder | ||
} | ||
} | ||
|
||
private func updateState() { | ||
if isDisabled { | ||
self.isEditable = false | ||
self.layer.borderColor = HandySemantic.bgBasicLight.cgColor | ||
placeholderLabel?.textColor = HandySemantic.textBasicDisabled | ||
} else if isNegative { | ||
self.isEditable = true | ||
self.layer.borderColor = HandySemantic.lineStatusNegative.cgColor | ||
placeholderLabel?.textColor = HandySemantic.textBasicTertiary | ||
} else { | ||
self.isEditable = true | ||
self.layer.borderColor = HandySemantic.bgBasicLight.cgColor | ||
placeholderLabel?.textColor = HandySemantic.textBasicTertiary | ||
} | ||
} | ||
|
||
|
||
public override func layoutSubviews() { | ||
super.layoutSubviews() | ||
|
||
if let minHeight = minHeight, let maxHeight = maxHeight { | ||
isScrollEnabled = contentSize.height > maxHeight || contentSize.height < minHeight | ||
} else if let maxHeight = maxHeight { | ||
isScrollEnabled = contentSize.height > maxHeight | ||
} | ||
|
||
else if let minHeight = minHeight, bounds.height < minHeight { | ||
invalidateIntrinsicContentSize() | ||
frame.size.height = minHeight | ||
} | ||
|
||
else if let maxHeight = maxHeight, bounds.height > maxHeight { | ||
invalidateIntrinsicContentSize() | ||
frame.size.height = maxHeight | ||
} | ||
|
||
scrollIndicatorInsets = UIEdgeInsets( | ||
top: 0, | ||
left: 0, | ||
bottom: 0, | ||
right: HandyTextViewConstants.Dimension.scrollIndicatorInsets | ||
) | ||
} | ||
|
||
@objc private func textDidChange() { | ||
placeholderLabel?.isHidden = !text.isEmpty | ||
} | ||
} | ||
|
||
// MARK: - UITextViewDelegate | ||
|
||
extension HandyBaseTextView: UITextViewDelegate { | ||
public func textViewDidBeginEditing(_ textView: UITextView) { | ||
if !isNegative { | ||
self.layer.borderColor = HandySemantic.lineStatusPositive.cgColor | ||
} | ||
} | ||
|
||
public func textViewDidEndEditing(_ textView: UITextView) { | ||
updateState() | ||
} | ||
|
||
public func textViewDidChange(_ textView: UITextView) { | ||
textDidChange() | ||
} | ||
} |
Oops, something went wrong.