티스토리 뷰

계속해서 아이디 입력창 아래 Label을 바꿔서 보여주는 기능을 생각해볼 예정이다

 

이전 포스팅에서는 label이 없어졌다가 유저가 Text Field창과 상호작용하면 Label이 나타나게 되고, Edting 할때마다(changed)  메서드를 작동시키게 연결하는 것까지 진행했다

 

text의 조건 확인하기(글자 수, 소문자, 정규표현식의 문자 조건 (알파벳소문자, 숫자, 길이)확인)

일단 idTextFieldTyped 함수 내의 코드들을 아래처럼 수정해주자 

    @IBAction func idTextFieldTyped(_ sender: UITextField) {
        idTextFieldDescription.isHidden = false // label 보여주기
        
        let userWord = idTextField.text?.lowercased() // 소문자 변환
        idTextField.text = userWord // 변환된 소문자로 바꿔주기
        
        let minCount = 5
        let maxCount = 12
        let count = userWord!.count

        switch count {
        case 0:
            idTextFieldDescription.text = "아이디는 필수입력 정보입니다."
        case 1..<minCount:
            idTextFieldDescription.text = "아이디는 5글자 이상이어야 합니다."
        case minCount...maxCount:
            let idPattern = "^[a-z0-9-_]{\(minCount),\(maxCount)}$"
            let isVaildPattern = (userWord!.range(of: idPattern, options: .regularExpression) != nil)
            if isVaildPattern {
                idTextFieldDescription.text = "조건에 맞는 아이디"
                idTextFieldDescription.isHidden = true
            } else {
                idTextFieldDescription.text = "소문자, 숫자, 빼기(-), 밑줄(_)만 사용할 수 있습니다."
            }
        default:
            idTextFieldDescription.text = "아이디는 12글자 이하이어야 합니다."
        }

lowercase()를 사용해서 소문자로 변환한 후 user가 입력한 text를 바꿔주었고,

글자수를 기준으로 switch 구문으로 case 처리했다

글자수가 적절할 때에는 조건을 정규표현식으로 구분해서 text를 입력하거나 사라지게 처리해주었다

값이 입력되지 않은 상황
4글자 이하인 상황
13글자 이상인 상황
조건 외의 문자가 들어간 경우
조건에 맞는 상황

 

비슷한 방법으로 비밀번호, 이메일, 휴대폰번호, 인증번호의 label도 조건을 만들어주자

 

+ label의 textColor를 red로 변경해주는 것은 반복작업이라 viewDidLoad안의 defaultHiddenCollection for 함수 내로 이동시켜주었다.

+ 휴대폰 번호 Text Field 아래에도 label을 추가해주었고, 인증번호 왼쪽에도 확인 버튼을 추가해주었다

+ idTextFieldTyped 함수에 idTextField의 "Did End on Exit" 이벤트도 connection 해주었다

 

다 추가해준 뒤 소스코드

//
//  ViewController.swift
//  practiceCommerce01
//
//  Created by Brother Model on 2022/07/12.
//
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var defaultHiddenCollection: [UILabel]!
    
    @IBOutlet weak var idTextField: UITextField!
    @IBOutlet weak var idTextFieldDescription: UILabel!
    
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var passwordTextFieldDescription: UILabel!
    
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var emailTextFieldDescription: UILabel!
    
    @IBOutlet weak var phoneNumberTextField: UITextField!
    @IBOutlet weak var phoneNumberTextFieldDescription: UILabel!
    
    @IBOutlet weak var phoneNumberCheckTextField: UITextField!
    @IBOutlet weak var phoneNumberCheckTextFieldDescription: UILabel!
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        for label in defaultHiddenCollection {
            label.isHidden = true
            label.textColor = .red
        }

    }

    @IBAction func idTextFieldTyped(_ sender: UITextField) {
        idTextFieldDescription.isHidden = false
        
        let userWord = idTextField.text?.lowercased()
        idTextField.text = userWord
        
        let minCount = 5
        let maxCount = 12
        let count = userWord!.count

        switch count {
        case 0:
            idTextFieldDescription.text = "아이디는 필수입력 정보입니다."
        case 1..<minCount:
            idTextFieldDescription.text = "아이디는 5글자 이상이어야 합니다."
        case minCount...maxCount:
            let idPattern = "^[a-z0-9-_]{\(minCount),\(maxCount)}$"
            let isVaildPattern = (userWord!.range(of: idPattern, options: .regularExpression) != nil)
            if isVaildPattern {
                idTextFieldDescription.text = "조건에 맞는 아이디"
                idTextFieldDescription.isHidden = true
            } else {
                idTextFieldDescription.text = "소문자, 숫자, 빼기(-), 밑줄(_)만 사용할 수 있습니다."
            }
        default:
            idTextFieldDescription.text = "아이디는 12글자 이하이어야 합니다."
        }
    }
    
    @IBAction func passwordTextFieldTyped(_ sender: UITextField) {
        passwordTextFieldDescription.isHidden = false
        
        let minCount = 8
        let maxCount = 16
        let count = passwordTextField.text!.count

        switch count {
        case 0:
            passwordTextFieldDescription.text = "비밀번호는 필수입력 정보입니다."
        case 1..<minCount:
            passwordTextFieldDescription.text = "비밀번호는 8글자 이상이어야 합니다."
        case minCount...maxCount:
            let idPattern = #"^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{\#(minCount),\#(maxCount)}$"#
            let isVaildPattern = (passwordTextField.text!.range(of: idPattern, options: .regularExpression) != nil)
            if isVaildPattern {
                passwordTextFieldDescription.text = "조건에 맞는 비밀번호"
                passwordTextFieldDescription.isHidden = true
            } else {
                passwordTextFieldDescription.text = "영어알파벳, 숫자, 특수문자가 필수로 입력되어야 합니다."
            }
        default:
            passwordTextFieldDescription.text = "비밀번호는 16글자 이하이어야 합니다."
        }
    }
    
    @IBAction func emailTextFieldTyped(_ sender: UITextField) {
        emailTextFieldDescription.isHidden = false
        
        let idPattern = #"^[a-zA-Z0-9+-\_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"#
        let isVaildPattern = (emailTextField.text!.range(of: idPattern, options: .regularExpression) != nil)
        
        if emailTextField.text!.isEmpty {
            emailTextFieldDescription.text = "이메일은 필수로 입력해야합니다"
        } else if isVaildPattern {
            emailTextFieldDescription.text = "조건에 맞는 이메일"
            emailTextFieldDescription.isHidden = true
        } else {
            emailTextFieldDescription.text = "올바르지 않은 이메일 형식입니다"
        }
    }
        
    @IBAction func phoneTextFieldTyped(_ sender: UITextField) {
        phoneNumberTextFieldDescription.isHidden = false
        let convertDigit = phoneNumberTextField.text!.replacingOccurrences(of: #"\D"#, with: "", options: .regularExpression)
        let count = convertDigit.count
        switch count {
        case 0:
            phoneNumberTextFieldDescription.text = "휴대폰 번호는 필수로 입력해야합니다"
            phoneNumberTextField.text = convertDigit
        case 1...3:
            phoneNumberTextField.text = convertDigit
        case 4...7:
            phoneNumberTextField.text = convertDigit.prefix(3) + "-" + convertDigit.suffix(convertDigit.count-3)
            phoneNumberTextFieldDescription.text = "올바르지 않은 휴대폰 번호 입니다"
        case 8...11:
            let startIndex = convertDigit.index(convertDigit.startIndex, offsetBy: 3)
            let endingIndex = convertDigit.index(convertDigit.startIndex, offsetBy: count-5)
            let middleNumber = convertDigit[startIndex...endingIndex]
            phoneNumberTextField.text = convertDigit.prefix(3) + "-" + middleNumber + "-" + convertDigit.suffix(4)
            phoneNumberTextFieldDescription.text = "올바른 휴대폰 번호입니다"
            phoneNumberTextFieldDescription.isHidden = true
        default:
            phoneNumberTextFieldDescription.text = "올바르지 않은 휴대폰 번호입니다"
        }
    }
    
    @IBAction func phoneNumberCheckTextFieldTyped(_ sender: UITextField) {
        phoneNumberCheckTextFieldDescription.isHidden = false
        let convertDigit = phoneNumberCheckTextField.text!.replacingOccurrences(of: #"\D"#, with: "", options: .regularExpression)
        phoneNumberCheckTextField.text = convertDigit
        let count = convertDigit.count
        switch count {
        case 0:
            phoneNumberCheckTextFieldDescription.text = "인증번호를 입력해주세요"
        case 6:
            phoneNumberCheckTextFieldDescription.isHidden = true
        default:
            phoneNumberCheckTextFieldDescription.text = "인증번호는 6자리 숫자 입니다."
        }
    }   
}

정신 없지만 조금씩 설명을 해보자면, 

 

비밀번호는 먼저 문자 개수를 count 해서 조건을 나눴고, 8글자 이상 16글자 이하인 경우에는

알파벳, 숫자, 특수문자를 정규식으로 한번 검증한 후 Label을 없애주거나 알파벳, 숫자, 특수문자가 필수로 입력되어야 한다고 Label을 바꾸도록 만들었다

 

text field에 커서 올랐을 때(빈칸인 경우) 필수 입력 표시를 해준 후 타이핑 이후에는 정규표현식으로 이메일 형식만 맞는지 확인했다

 

휴대폰 번호는 text field의 값을 계속 받아서 정규표현식(\D)을 통해서 숫자가 아닌 경우를 ""으로 바꾸는 작업을 하고,

그다음 적혀진 번호들을 count 해서 각각 3, 7자리 뒤에 빼기(-) 기호를 자동으로 넣어서 돌려지도록 만들었다

(세상에... 문자열 인덱싱 이렇게 복잡한게 실화...)

 

휴대폰 인증번호는 휴대폰 번호와 마찬가지로 숫자 외의 단어나 기호는 입력되지 않도록(""로 바꿔서 돌려줌) 작업한 후,

빈 칸일 때는 입력해달라는 Label을, 6자리가 아닌 경우에는 6자리 숫자임을 알리도록 나타나게 했다

 

Label이 모두 표시됐을 때 화면은 아래와 같다

 

버튼 액션을 통해 view 보이게 하기

휴대폰 인증번호를 입력하는 부분은 휴대폰 번호를 입력하기 전까지에는 보여주지 않다가,

휴대폰 번호를 입력한 후 인증 버튼을 보이면 나타나게 하고 싶다

isHidden 처리를 하는 것은 똑같은데, 버튼에 액션을 추가해서 실행시켜보자

인증 UIButton을 control로 클릭한 후 IBAction 선언, connect 해보자

Name을 적절하게 작성해주고, Type는 UIButton으로 바꿔주었다(아래 사진 참고)

버튼을 눌렀을 때, 보여주기 위해서는 먼저 숨김처리 되어있어야하니 버튼 액션에 코드를 넣기 전에 대상을 지정할 필요가 있다.

 

 

Stack View로 객체들을 묶어주기

인증번호 Label, TextField, Button, Description Label들을 다 숨김처리해놓았다가 보여줘야 하니

일단 대상들을 하나로 묶어주자

Interface Builder에서 한묶음으로 선택하거나 Document Outline에서 한번에 클릭한 후 

Interface Builder 오른쪽 하단에 보이는 네모안으로 들어가는 아래 화살표 아이콘을 선택하자

그다음 stack view로 묶어주자

정확히는 text field와 인증버튼을 가로로 놓고 먼저 Stack View로 묶어주고, 그다음 나머지를 다시 stack View로 묶어주자

아래아래 사진의 Document Outline을 보면 묶여있는 View 그룹 트리를 확인 할 수 있다

수평(horizontal), 수직(Vertical) 속성은 View의 attributes inspector의 axis에서 변경할 수 있다.

Stack View로 묶였으면 다른 객체들처럼 Outlet을 선언해주고 connect 해주자

 

viewDidLoad에서

        phoneNumberView.isHidden = true

코드를 넣어주면 기본적으로 숨김처리가 된다

 

다시 인증버튼을 눌렀을 때 묶어놓은 view를 보여주도록 작성해보자

인증이라는 텍스트를 누른 후에 변화를 주고 싶어서 "인증"이라는 title을 "전송"으로 바꾸고,

버튼을 누르면 "재전송"으로 바꾸게 해보자

인증 버튼도 Outlet 선언, connect를 해주고 이전에 선언해놓았던 phoneNumberButtonClicked 함수에는 다음 코드를 넣으면 인증버튼을 눌렀을 때 아래 휴대폰번호 인증 Stack View가 나타나고, 버튼 title이 바뀐다

    @IBAction func phoneNumberButtonClicked(_ sender: UIButton) {
        phoneNumberView.isHidden = false
        phoneNumberButton.setTitle("재전송", for: .normal)
    }

 

여기서 테스트를 하면서 알게 되었는데...

휴대폰 번호 형식이 8~9자리인 경우에도 label이 사라지는 것을 확인해서 함수를 조금 더 수정해주었다.

    @IBAction func phoneTextFieldTyped(_ sender: UITextField) {
        phoneNumberTextFieldDescription.isHidden = false
        let convertDigit = phoneNumberTextField.text!.replacingOccurrences(of: #"\D"#, with: "", options: .regularExpression)
        let count = convertDigit.count
        let rightNumberCount = [10, 11]
        switch count {
        case 0:
            phoneNumberTextFieldDescription.text = "휴대폰 번호는 필수로 입력해야합니다"
            phoneNumberTextField.text = convertDigit
        case 1...3:
            phoneNumberTextField.text = convertDigit
        case 4...7:
            phoneNumberTextField.text = convertDigit.prefix(3) + "-" + convertDigit.suffix(convertDigit.count-3)
            phoneNumberTextFieldDescription.text = "올바르지 않은 휴대폰 번호 입니다"
        case 8...11:
            let startIndex = convertDigit.index(convertDigit.startIndex, offsetBy: 3)
            let endingIndex = convertDigit.index(convertDigit.startIndex, offsetBy: count-5)
            let middleNumber = convertDigit[startIndex...endingIndex]
            phoneNumberTextField.text = convertDigit.prefix(3) + "-" + middleNumber + "-" + convertDigit.suffix(4)
            if rightNumberCount.contains(count) {
                phoneNumberTextFieldDescription.text = "올바른 휴대폰 번호입니다"
                phoneNumberTextFieldDescription.isHidden = true
            } else {
                phoneNumberTextFieldDescription.text = "올바르지 않은 휴대폰 번호입니다"
            }
        default:
            phoneNumberTextFieldDescription.text = "올바르지 않은 휴대폰 번호입니다"
        }
    }

rightNumberCount라는 상수를 만들고 count가 조건을 만족하고 rightNumberCount 배열에 있을 때는 Label을 숨겨주고 그게 아닐 때는 올바르지 않은 휴대폰 번호라고 나타내준다

 

 

현재 상태에서는 

휴대폰 번호를 입력한 후 전송을 눌렀을 때,

휴대폰 번호 상태와 상관없이 아래 인증번호 체크 view가 보여지며, 전송완료로 바뀌는데

휴대폰 번호 조건을 확인한 후 올바른 휴대폰번호가 아니면 alert를 띄우고 바뀌지 않도록 할 예정이다

같은 코드가 반복되는 부분도 있는데 여유가 되면 따로 함수를 빼서 호출할 수 있도록 해보려고 한다..

 

맥주 한캔 하고 싶은데 술 마실 시간도 없는거 실환가.. 싶지만 잘마시고 있음

댓글