Visual_Novel_iOS/crush/Crush/Src/Components/UI/TextViews/CLTextField.swift

352 lines
11 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CLTextField.swift
// Crush
//
// Created by Leon on 2025/7/15.
//
import UIKit
class CLTextField: UITextField {
// MARK: - Properties
private var focusBorderColor: UIColor = .orange
private var errorBorderColor: UIColor = .red
private var nowBorderColor: UIColor = .clear
private var tapTopButtonAction: (() -> Void)?
/// errorBorder border
private var errorBorderShowMode: Bool = false
private var alwaysShowRightViewConfig: Bool = false
private var alwaysShowClearButtonIfHave: Bool = false
private var disableAllBorder: Bool = false
private var fakeTextFieldForInputTrigger: Bool = false
var cornerRadiusConfig:CGFloat = 8
// private var defaultTxt: String?
// Closures for delegate-like events (assumed from Objective-C)
var textDidChanged: ((CLTextField) -> Void)?
var textDidBeginEditing: ((CLTextField) -> Void)?
var textDidEndEditing: ((CLTextField) -> Void)?
var textShouldBeginEditing: ((CLTextField) -> Bool)?
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
baseCommonSetup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
baseCommonSetup()
}
private func baseCommonSetup() {
// keyboardAppearance = .dark
// reloadInputViews()
setContentHuggingPriority(UILayoutPriority(244), for: .horizontal)
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
leftView.backgroundColor = .clear
self.leftViewMode = .always
self.leftView = leftView
// --- 3 events
addTarget(self, action: #selector(textDidChanged(_:)), for: .editingChanged)
NotificationCenter.default.addObserver(self, selector: #selector(notiTextDidBeginEditing), name: UITextField.textDidBeginEditingNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(notiTextDidEndEditing), name: UITextField.textDidEndEditingNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(notiTextShouldBeginEditing(_:)), name: UITextField.textDidBeginEditingNotification, object: self)
setupStandard()
}
// MARK: - Public Methods
func setupStandard() {
autocorrectionType = .no
backgroundColor = .c.csen
font = CLSystemToken.font(token: .tbl)
textColor = .white
focusBorderColor = .theme
errorBorderColor = .red
layer.borderWidth = 1
layer.borderColor = UIColor.clear.cgColor
layer.cornerRadius = cornerRadiusConfig
// NSLayoutConstraint.activate([
// heightAnchor.constraint(equalToConstant: 48)
// ])
snp.makeConstraints { make in
make.height.equalTo(48)
}
// default
setupRightClearButton()
}
func setupPlaceholder(_ placeholder: String) {
let font = UIFont.systemFont(ofSize: 15)
let color = UIColor.gray
let attributes: [NSAttributedString.Key: Any] = [
.font: font,
.foregroundColor: color
]
attributedPlaceholder = NSAttributedString(string: placeholder, attributes: attributes)
}
func setupTopButton(with action: (() -> Void)?) {
let topButton = UIButton(type: .custom)
topButton.backgroundColor = .clear
addSubview(topButton)
topButton.addTarget(self, action: #selector(tapTopButton), for: .touchUpInside)
tapTopButtonAction = action
// Using SnapKit or native Auto Layout
topButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
topButton.topAnchor.constraint(equalTo: topAnchor),
topButton.bottomAnchor.constraint(equalTo: bottomAnchor),
topButton.leadingAnchor.constraint(equalTo: leadingAnchor),
topButton.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}
func showAlwayErrorBorder() {
errorBorderShowMode = true
layer.borderWidth = 1
layer.borderColor = errorBorderColor.cgColor
}
func hideErrorBorder() {
errorBorderShowMode = false
layer.borderColor = UIColor.clear.cgColor
}
func sendTextChangedNoti(){
NotificationCenter.default.post(
name: UITextField.textDidChangeNotification,
object: self)
}
// MARK: - Helper Methods
func setupRightClearButton() {
rightViewMode = .whileEditing
let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
self.rightView = rightView
let clearButton = EPIconGhostSecondaryButton(radius: .none, iconSize: .small, iconCode: .delete02)
rightView.addSubview(clearButton)
clearButton.addTarget(self, action: #selector(tapClearButton), for: .touchUpInside)
clearButton.snp.makeConstraints { make in
make.size.equalTo(clearButton.bgImageSize())
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().offset(-8)
}
}
func setupRightEyeButton() {
isSecureTextEntry = true
rightViewMode = .always
alwaysShowRightViewConfig = true
let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
self.rightView = rightView
}
func setupRightRightArrowButton() -> UIButton? {
rightViewMode = .always
alwaysShowRightViewConfig = true
let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
self.rightView = rightView
return nil
}
func setupRightViewEmpty() {
rightView = nil
}
func setupLeftCoinIconView() {
leftViewMode = .always
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 40))
let iconView = UIImageView(frame: CGRect(x: 16, y: 12, width: 16, height: 16))
iconView.image = UIImage(named: "icon_16_diamond")
leftView.addSubview(iconView)
self.leftView = leftView
}
func setupLeftBlankView() {
leftViewMode = .always
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 40))
self.leftView = leftView
}
func adjustRightViewMode() {
if alwaysShowRightViewConfig {
rightViewMode = .always
return
}
//
if text?.isEmpty ?? true {
rightViewMode = .never
} else {
rightViewMode = alwaysShowClearButtonIfHave ? .always : .whileEditing
}
}
// MARK: - Actions
@objc private func tapTopButton() {
tapTopButtonAction?()
}
@objc private func tapClearButton() {
text = ""
textDidChanged(self)
NotificationCenter.default.post(
name: UITextField.textDidChangeNotification,
object: self)
}
@objc private func tapRightArrowButton(_ button: UIButton) {
// Empty implementation as in original
}
// MARK: - Textfield Events
@objc private func textDidChanged(_ textField: UITextField) {
errorBorderShowMode = false
nowBorderColor = focusBorderColor
if !disableAllBorder && textField.isFirstResponder {
layer.borderColor = nowBorderColor.cgColor
}
adjustRightViewMode()
textDidChanged?(self)
}
@objc private func notiTextDidBeginEditing() {
if !errorBorderShowMode && !disableAllBorder {
layer.borderColor = focusBorderColor.cgColor
layer.borderWidth = 1
}
textDidBeginEditing?(self)
adjustRightViewMode()
}
@objc private func notiTextDidEndEditing() {
if !errorBorderShowMode {
layer.borderColor = nil
layer.borderWidth = 0
}
textDidEndEditing?(self)
}
@objc private func notiTextShouldBeginEditing(_ notification: Notification) {
if fakeTextFieldForInputTrigger {
resignFirstResponder()
}
textShouldBeginEditing?(self)
}
// MARK: - Setters
override var delegate: UITextFieldDelegate? {
get { super.delegate }
set {
if newValue !== self {
// print("block") // Uncomment if assertion is needed
}
super.delegate = newValue
}
}
override var placeholder: String? {
didSet {
if let placeholder = placeholder {
setupPlaceholder(placeholder)
}
}
}
// var defaultTxt: String? {
// get { _defaultTxt }
// set {
// _defaultTxt = newValue
// super.text = newValue
// }
// }
override var text: String? {
didSet {
if text != oldValue {
textDidChanged(self)
}
}
}
// MARK: - Layout
override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
var rightViewRect = super.rightViewRect(forBounds: bounds)
if #available(iOS 13.0, *) {
// fix iOS 13 rightView,
let left = frame.size.width - (rightView?.frame.size.width ?? 0)
let top = round((frame.size.height - (rightView?.frame.size.height ?? 0)) / 2.0)
rightViewRect = CGRect(x: left, y: top, width: rightView?.frame.size.width ?? 0, height: rightView?.frame.size.height ?? 0)
}
return rightViewRect
}
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = self.cornerRadiusConfig
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
extension CLTextField{
func switchToNaviSearchField(){
setupPlaceholder("Search")
font = .t.tbm
cornerRadiusConfig = 16// height: 32
snp.updateConstraints { make in
make.height.equalTo(32)
}
leftViewMode = .always
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 32))
leftView.snp.makeConstraints { make in
make.size.equalTo(CGSize(width: 40, height: 32))
}
self.leftView = leftView
let image = MWIconFont.image(fromIcon: .search, size: CGSize(width: 12, height: 12), color: .white)
let icon = UIImageView(image: image)
leftView.addSubview(icon)
icon.snp.makeConstraints { make in
make.size.equalTo(CGSize(width: 12, height: 12))
make.centerY.equalToSuperview()
make.leading.equalToSuperview().offset(12)
}
setNeedsLayout()
layoutIfNeeded()
}
}