UITextField 커스텀 클래스
- 자간, 줄간격
- 언더라인 (컬러, 두깨)
- Padding 조절
- tintClearImage Button
import UIKit
let LEFT_IMAGE_WIDTH: CGFloat = 16.0
let LEFT_IMAGE_HEIGHT: CGFloat = 16.0
let LEFT_TEXT_PADDING: CGFloat = 15.0
let RIGHT_BUTTON_PADDING: CGFloat = 10.0 // |5-button-5|
enum ViewType {
case left, right, textpadding
}
@IBDesignable
class IBTextField: UITextField {
var tintedClearImage: UIImage? = nil
private var underLineborder: CALayer? = nil
//private var leftPadingView: UIView? = nil
//private var leftImageView: UIImageView? = nil
@IBInspectable public var _fontStyleNumber: Int = 2{
didSet {
configure()
}
}
@IBInspectable public var _fontSize: CGFloat = 14.0{
didSet {
configure()
}
}
@IBInspectable public var _hintfontSize: CGFloat = 10{
didSet {
configure()
}
}
@IBInspectable public var _hintText: String = ""{
didSet {
configure()
}
}
/// Hint 텍스트 컬러
@IBInspectable public var _hintColor: UIColor = .white{
didSet {
configure()
}
}
/// 글자간격
@IBInspectable open var letterSpacing:CGFloat = 0.0 {
didSet {
configure()
}
}
/// 줄간격 default : 21
@IBInspectable open var linesspacing:CGFloat = -1.0 {
didSet {
configure()
}
}
/// 우측 Close 디폴트 버튼 컬러
@IBInspectable public var _closeTintColor: UIColor = .white{
didSet {
configure()
}
}
/// 테두리 두께
@IBInspectable public var _borderWidth: CGFloat = 0.0{
didSet {
self.layer.borderWidth = _borderWidth
}
}
/// 테두리 컬러
@IBInspectable public var _borderColor: UIColor = UIColor.white{
didSet {
self.layer.borderColor = self._borderColor.cgColor
}
}
/// 하단 BorderLine 사용 유무
@IBInspectable public var isUnderLine: Bool = false{
didSet {
makeUnderLine()
}
}
/// 하단 BorderLine 컬러
@IBInspectable public var underLineColor: UIColor = .red{
didSet {
makeUnderLine()
}
}
/// 하단 BorderLine 두께
@IBInspectable public var underLineHeight: CGFloat = 2.0 {
didSet {
makeUnderLine()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func layoutSubviews() {
super.layoutSubviews()
configure()
makeUnderLine()
rightCloseImageTintColor()
}
func configure() {
if _fontStyleNumber >= 0 || _fontStyleNumber <= 5{
if let fontStyle = FontStyleNumber.init(rawValue: _fontStyleNumber) {
// placeholder (Hint Text) Font
let hintSytlefont = UIFont.notoSansFont(forFont: fontStyle.fontName, size: _hintfontSize)
self.attributedPlaceholder = NSAttributedString(string: _hintText, attributes: [
.foregroundColor: _hintColor.withAlphaComponent(0.4),
.font: hintSytlefont
])
// Lable Text Font
self.font = UIFont.notoSansFont(forFont: fontStyle.fontName, size: _fontSize)
}
}
makeUnderLine()
setNeedsDisplay()
invalidateIntrinsicContentSize()
}
func makeUnderLine(){
if self.isUnderLine == false { return }
let frame = self.frame
if underLineborder == nil {
underLineborder = CALayer()
self.layer.addSublayer(underLineborder!)
}
underLineborder!.frame = CGRect(x: 0, y: frame.size.height-underLineHeight, width: frame.width, height: underLineHeight)
underLineborder!.backgroundColor = underLineColor.cgColor
setNeedsDisplay()
invalidateIntrinsicContentSize()
}
// 디폴트 우측 x버튼 컬러 변경 (기본적으로 투명도가 적용되있음)
private func rightCloseImageTintColor() {
for view in subviews {
if view is UIButton {
let button = view as! UIButton
if #available(iOS 13.0, *) {
// 컬러 뚜렷하게 표시 됨.
if let image = button.image(for: .normal)?.withTintColor(self._closeTintColor, renderingMode: .alwaysOriginal) {
button.setImage(image, for: .normal)
button.setImage(image, for: .highlighted)
}
} else {
// Fallback on earlier versions
// 컬러 투명적용되서 색이 뚜렷하게 표시 안됨.
if let image = button.image(for: .normal) {
tintedClearImage = self.tintImage(image: image, color: UIColor.white)
button.setImage(self.tintedClearImage, for: .normal)
button.setImage(self.tintedClearImage, for: .highlighted)
}
}
}
}
}
private func tintImage(image: UIImage, color: UIColor) -> UIImage {
let size = image.size
UIGraphicsBeginImageContextWithOptions(size, false, image.scale)
let context = UIGraphicsGetCurrentContext()
image.draw(at: .zero, blendMode: CGBlendMode.normal, alpha: 1.0)
context?.setFillColor(color.cgColor)
context?.setBlendMode(CGBlendMode.sourceIn)
context?.setAlpha(1.0)
let rect = CGRect(x: CGPoint.zero.x, y: CGPoint.zero.y, width: image.size.width, height: image.size.height)
UIGraphicsGetCurrentContext()?.fill(rect)
let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return tintedImage ?? UIImage()
}
// 왼쪽 이미지 아이콘 추가
func setMakeLeftImageView(image named: String) {
if let leftImage = UIImage(named: named) {
let leftImageView = UIImageView(frame:CGRect(x: 0.0, y: 0.0, width: LEFT_IMAGE_WIDTH, height: LEFT_IMAGE_HEIGHT))
leftImageView.contentMode = .center
leftImageView.image = leftImage
setView(.left, with: leftImageView)
}
setNeedsDisplay()
invalidateIntrinsicContentSize()
}
// 오른쪽 커스텀 Close 버튼 추가
func setMakeRightButtonView(rightButton: UIButton) {
let rightPadingView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: rightButton.frame.width, height: self.frame.height))
rightPadingView.tag = 1000
rightButton.tag = 2000
rightButton.center = CGPoint(
x: rightPadingView.bounds.size.width / 2,
y: rightPadingView.bounds.size.height / 2
)
rightPadingView.addSubview(rightButton)
setView(.right, with: rightPadingView)
setNeedsDisplay()
invalidateIntrinsicContentSize()
}
func setView(_ type: ViewType, with view: UIView) {
if type == ViewType.left || type == ViewType.textpadding {
leftView = view
leftViewMode = .always
} else if type == .right {
rightView = view
rightViewMode = .always
}
}
/* 왼쪽 아이콘 사용 안 할 경우 Text가 붙어서 입력되기 때문에 Padding 적용
- Text 입력시 왼쪽 Padding 적용
*/
func setMakeTextPadding(leftPadding: CGFloat = LEFT_TEXT_PADDING) {
let leftPadingView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: leftPadding, height: self.frame.height))
leftPadingView.contentMode = .center
setView(.textpadding, with: leftPadingView)
setNeedsDisplay()
invalidateIntrinsicContentSize()
}
// right 버튼 숨김/노출 설정
func rightButtonVisible(bHidden: Bool) {
guard let rightView = getView(viewTag: 1000) as? UIView else {
return
}
guard let rightButton = rightView.getView(viewTag: 2000) as? UIButton else {
return
}
rightButton.isHidden = bHidden
}
// 글자간격 및 줄간격 조정
func updateWithSpacing() {
let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
// 자간 간격 설정
attributedString.addAttribute(NSAttributedString.Key.kern, value: self.letterSpacing, range: NSRange(location: 0, length: attributedString.length))
// 줄간격 (default - 21)
if linesspacing > 0 {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = linesspacing
paragraphStyle.maximumLineHeight = linesspacing
paragraphStyle.alignment = self.textAlignment
attributedString.addAttribute(NSAttributedString.Key.font, value: self.font!, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
}
self.attributedText = attributedString
}
}
[사용방법]
IBDesignable 클래스라서 스토리보드상에서 설정하고 사용하는게 편하고 사용방법은 일반적인 UITextField 와 동일하다.
class ChatViewController: UIViewController {
@IBOutlet weak var chattingInputTextField: ITextField! {
didSet {
//우측 아이콘 표시
rightImageTextField.borderStyle = .none
rightImageTextField.keyboardType = .numberPad
rightImageTextField.returnKeyType = .next
rightImageTextField.setMakeLeftImageView(image: "phone_reg")
/*좌측 버튼 표시
사용 안할 경우 디폴트 x버튼 표시됨.*/
//let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 30))
let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
// 1. 이미지 버튼
rightButton.contentMode = .center
rightButton.setImage(UIImage(named: "close"), for: .normal)
// 2. 텍스트 버튼
//rightButton.titleLabel?.textColor = UIColor.gray
//rightButton.titleLabel?.font = UIFont.notoSansFont(forFont: .NotoSansCJKkrRegular, size: 9)
//rightButton.setTitle("재전송", for: .normal)
rightImageTextField.setMakeRightButtonView(rightButton: rightButton)
//right button Click 이벤트 연결
rightButton.addTarget(self, action: #selector(buttonPressed(_:)), for: .touchUpInside)
//TextField 입력 이벤트 연결
rightImageTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
}
override func viewDidLoad() {
super.viewDidLoad()
chattingInputTextField.delegate = self
chattingInputTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
setBecomeFirstResponder()
}
/// 채팅 입력창 키보드 바로 표시
func setBecomeFirstResponder() {
// 채팅입력창 포커스 활성화
self.chattingInputTextField.becomeFirstResponder()
}
}
extension ChatViewController : UITextFieldDelegate {
@objc func textFieldDidChange(_ textField: UITextField) {
}
/// 키보드 리턴키 델리게이트 처리
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print("textFieldShouldReturn: \((textField.text) ?? "Empty")")
// 최종 입력된 정보가 있으면 전송 후 텍스트 필드 초기화
sendChattingMessage(message: textField.text)
return true
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
print("textFieldShouldClear: \((textField.text) ?? "Empty")")
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("shouldChangeCharactersIn: \((textField.text) ?? "Empty")")
let currentText = textField.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
self.chattingSendButton.isEnabled = updatedText.count >= 1 ? true:false
return true
}
}
'Swift > UITextField' 카테고리의 다른 글
[SWIFT]UITextField 정규식 입력정보 설정하기 (0) | 2023.07.20 |
---|---|
[SWIFT]키보드 올라오는 속도에 맞춰 TextField 이동 (0) | 2023.06.15 |
[SWIFT]입력된 텍스트 뒤에서 부터 하나씩 삭제하기 (0) | 2023.06.09 |
[SWIFT]키보드 handler Event TextField 키보드 위/아래 이동 (0) | 2023.06.09 |