Swift/UIView
[SWIFT]커스텀 숫자키패드 한줄배열 및 두줄배열/ UITextField 커스텀 키보드
삽질중
2023. 6. 9. 10:41
프로젝트에서 사용해야되서 만든 숫자키패드 커스텀 UI 1줄 또는 2줄로 배열됨
import UIKit
let NUMBER_TAG = 1
let BACK_TAG = 99
let CLOSE_TAG = 100
let VERTICAL_HEIGHT: CGFloat = 130//117 // 세로모드 키패드 사이즈 (2 줄)
let HORIZONTAL_HEIGHT: CGFloat = 70 // 가로모드 키패드 사이즈 (1 줄)
let BTN_WIDTH: CGFloat = 50.0
let BTN_HEIGHT: CGFloat = 45.0
let V_WIDTH_PADING: CGFloat = 10.0
let V_HEIGHT_PADING: CGFloat = 5.0
let H_WIDTH_PADING: CGFloat = 5.0
let H_HEIGHT_PADING: CGFloat = 5.0
enum PadType {
case HORIZONTAL // 1줄
case VERTICAL // 2줄
}
protocol CustomNumberKeyPadViewDelegate: class {
func numberKey(number key: String)
func backSpaceKey()
func CloseKey()
}
@IBDesignable
class CustomNumberKeyPadView: UIView {
weak var delegate: CustomNumberKeyPadViewDelegate?
var numberPad = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
var funcPad = ["Delete", "Close"]
@IBInspectable
public var fontSize: CGFloat = 12.0 {
didSet {
}
}
//for i in 0..<numberPad.count {
lazy var numberButtons: [IBCusomButton] = { [weak self] in
var padButtons: [IBCusomButton] = []
for i in 0..<(self?.numberPad.count)! {
let padBtn = IBCusomButton(frame: CGRect(x: 0, y: 0, width: BTN_WIDTH, height: BTN_HEIGHT))
padBtn.cornerRadius = 6.0
padBtn.setTitle(numberPad[i], for: .normal)
padBtn.fontsize = 16.0
padBtn.fontStyleNumber = 1
padBtn.setTitleColor(UIColor.white, for: .normal)
padBtn.setTitleColor(UIColor.white, for: .selected)
padBtn.setTitleColor(UIColor.white, for: .highlighted)
padBtn.isGradientUseHighlight = true
padBtn.isGradientBackground = true
padBtn.isGradientBorder = true
padBtn.gradientStartPoint = CGPoint(x: 0.0, y: 0.29)
padBtn.gradientEndPoint = CGPoint(x: 0.67,y: 1.0)
padBtn.gradientBGColors = [UIColor.pinkishGrey,UIColor.brownishGreyTwo]
padBtn.gradientBorderColors = [UIColor.greyish, UIColor.warmGrey]
padBtn.gradientHightlightedColors = [UIColor.azureTwo, UIColor.aquamarine]
padBtn.borderWidth = 2
padBtn.gradientBorderColors = [UIColor.greyish, UIColor.warmGrey]
padBtn.contentVerticalAlignment = .center
padBtn.tag = i + NUMBER_TAG
padBtn.addTarget(self, action: #selector(clickButton(_:)), for: .touchUpInside)
padButtons.append(padBtn as! IBCusomButton)
self?.addSubview(padBtn)
}
return padButtons
}()
lazy var deleteButton: UIButton = { [weak self] in
let deleteBtn = UIButton(frame: CGRect(x: 0, y: 0, width: BTN_WIDTH, height: BTN_HEIGHT))
// let deleteBtn = UIButton(frame: .zero)
deleteBtn.layer.cornerRadius = 6.0
deleteBtn.setImage(UIImage(named: "Keyboard_Back_Image"), for: .normal)
deleteBtn.setTitle("Delete".localized, for: .normal)
deleteBtn.titleLabel?.font = UIFont.notoSansFont(forFont: .NotoSansCJKkrRegular, size: 10.0)
deleteBtn.setTitleColor(UIColor.white, for: .normal)
deleteBtn.setTitleColor(UIColor.white, for: .selected)
deleteBtn.backgroundColor = UIColor.hexStringToUIColor(hex: "#000000", alpha: 0.23)
deleteBtn.borderColor(width: 1.0, borderColor: UIColor.white)
deleteBtn.tag = BACK_TAG
self?.alignTextBelow(button: deleteBtn, spacing: 2.0)
deleteBtn.addTarget(self, action: #selector(clickButton(_:)), for: .touchUpInside)
self?.addSubview(deleteBtn)
return deleteBtn
}()
lazy var closeButton: UIButton = { [weak self] in
let closeBtn = UIButton(frame: CGRect(x: 0, y: 0, width: BTN_WIDTH, height: BTN_HEIGHT))
// let closeBtn = UIButton(frame: .zero)
closeBtn.layer.cornerRadius = 6.0
closeBtn.setImage(UIImage(named: "Keyboard_Close_Image"), for: .normal)
closeBtn.setTitle("Close".localized, for: .normal)
closeBtn.titleLabel?.font = UIFont.notoSansFont(forFont: .NotoSansCJKkrRegular, size: 10.0)
closeBtn.setTitleColor(UIColor.white, for: .normal)
closeBtn.setTitleColor(UIColor.white, for: .selected)
closeBtn.backgroundColor = UIColor.hexStringToUIColor(hex: "#000000", alpha: 0.23)
closeBtn.borderColor(width: 1.0, borderColor: UIColor.white)
closeBtn.tag = CLOSE_TAG
self?.alignTextBelow(button: closeBtn, spacing: 2.0)
closeBtn.addTarget(self, action: #selector(clickButton(_:)), for: .touchUpInside)
self?.addSubview(closeBtn)
return closeBtn
}()
deinit {
// log(direction: .ETC, ofType: self, datas: "CustomNumberKeyPadView deinit")
// panelButtons.removeAll()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// setupView()
backgroundColor = .clear
}
override init(frame: CGRect) {
super.init(frame: frame)
// backgroundColor = UIColor.aquaBlue
// addButtonView()
setupView()
}
func setupView() {
let blurEffect:UIBlurEffect = UIBlurEffect(style: .dark)
let blurredEffectView = UIVisualEffectView(effect: blurEffect)
blurredEffectView.alpha = 1.0
self.insertSubview(blurredEffectView, at: 0)
blurredEffectView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
blurredEffectView.topAnchor.constraint(equalTo: self.topAnchor),
blurredEffectView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
blurredEffectView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
blurredEffectView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
override func layoutSubviews() {
super.layoutSubviews()
// self.backgroundColor = UIColor.clear
}
func alignTextBelow(button: UIButton, spacing: CGFloat) {
//let spacing: CGFloat = 6.0
if button.imageView != nil {
if let imageView = button.imageView {
let imageSize = imageView.frame.size
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0)
let titleSize = button.titleLabel!.frame.size
button.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0, bottom: 0, right: -titleSize.width)
}
}
}
func getPadViewFit(type: PadType) -> CGFloat {
if type == .VERTICAL {
// 세로모드 2라인
let contentWidth = BTN_WIDTH * (CGFloat(numberButtons.count/2) + 1)
let padingWidth = V_WIDTH_PADING * (CGFloat(numberButtons.count/2) + 1 - 1)
return contentWidth + padingWidth
} else {
// 가로모드 1라인
let contentWidth = BTN_WIDTH * (CGFloat(numberButtons.count) + 2)
let padingWidth = H_WIDTH_PADING * (CGFloat(numberButtons.count) + 2 - 1)
return contentWidth + padingWidth
}
}
func verticalLayerButtons() {
let contentWidth = getPadViewFit(type: .VERTICAL)
var start_x = (self.frame.width - contentWidth) / 2
// var start_y: CGFloat = 5.0
var start_y = (self.frame.height - (BTN_HEIGHT * 2 + V_WIDTH_PADING)) / 2
let linebreak = start_x
// print("<==> Portrait frame width \(self.frame.width) - getPadViewFit \(getPadViewFit(type: .VERTICAL)) / start_x \(start_x)")
for i in 0..<numberButtons.count {
numberButtons[i].frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
start_x += numberButtons[i].frame.width + V_WIDTH_PADING
if i == 4 {
// 1Line : 1...5 Close 버튼 추가
closeButton.frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
start_x = linebreak
start_y += closeButton.frame.height + V_HEIGHT_PADING
} else if i == 9{
// 2Line : 6...10 Delete 버튼 추가
deleteButton.frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
}
}
}
func horizontalLayerButtons() {
let leftPadding = UIApplication.getsafeAreaLeftMagin()
let rightPadding = UIApplication.getsafeAreaRightMagin()
let padding = CGFloat(leftPadding + rightPadding)
let contentWidth = getPadViewFit(type: .HORIZONTAL)
var start_x = (self.frame.width + padding - contentWidth) / 2
let start_y = (self.frame.height - (BTN_HEIGHT * 1)) / 2
// let start_y: CGFloat = 5.0
for i in 0..<numberButtons.count {
numberButtons[i].frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
start_x += numberButtons[i].frame.width + H_WIDTH_PADING
if i == 9{
// 1Line : 1...10 Delete,Close 버튼 추가
deleteButton.frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
start_x += deleteButton.frame.width + H_WIDTH_PADING
closeButton.frame = CGRect(x: start_x, y: start_y, width: BTN_WIDTH, height: BTN_HEIGHT)
}
}
}
@objc func clickButton(_ sender: UIButton) {
guard let delegate = self.delegate else {
print("CustomNumberKeyPadView Delegate NULL!!!!")
return
}
if sender.tag == CLOSE_TAG {
delegate.CloseKey()
}
if sender.tag == BACK_TAG {
delegate.backSpaceKey()
}
if let number = self.numberPad[safe: sender.tag - 1] {
delegate.numberKey(number: number)
}
}
}
예제) 스토리보드에 CustomNumberKeyPadView 설정 후 사용 (IBDesignable 사용)
extension KeyboardViewController: CustomNumberKeyPadViewDelegate {
func numberKey(number key: String) {
print("KeyboardSendBarViewController numberKey : \(key)")
//숫자 8자리까지 허용
if giftQuantityTextField.text!.count >= 8 {
return
}
let currentString = giftQuantityTextField.text! + key
giftQuantityTextField.text = currentString
}
func backSpaceKey() {
giftQuantityTextField.text = String(giftQuantityTextField.text!.dropLast(1))
}
func CloseKey() {
// UI 숨김처리
keypadCloseClosure?()
}
}
class KeyboardViewController: UIViewController {
@IBOutlet weak var giftQuantityTextField: UITextField! {
didSet {
giftQuantityTextField.isEnabled = false
giftQuantityTextField.text = "100"
}
}
@IBOutlet weak var numberKeypadView: CustomNumberKeyPadView!
var keypadCloseClosure: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
numberKeypadView.delegate = self
}
}
[TextField 에 커스텀 키보드 적용하기]
텍스트 필드 포커스 되면 기본 키보드가 아닌 커스텀 키보드가 올라오게 된다.
lazy var numberPadView: CustomNumberKeyPadView = { [weak self] in
let padView = CustomNumberKeyPadView(frame: .zero)
padView.delegate = self
giftQuantityTextField.inputView = padView
// giftQuantityTextField.inputView = UIView(frame: .zero)
// giftQuantityTextField.inputAccessoryView = padView
return padView
}()