연습장/실습
4주차_ SNS 앱 1. TextWatcher 유효성 검사
아이른
2024. 4. 1. 22:38
문제 1. 로그인, 회원 가입 페이지 ( SignInActivity, SignUpActivity )
- 비밀번호 입력 시, 보안을 유지하기 위해 마스킹 처리(***)로 표현해 주세요.
- 로그인 이후 사용자 이름이 보이게 하는 상세로직을 정해보세요.
- ex) data class 프로퍼티 넘기기, 캐싱 값 불러오기 등
문제 2. 로그인, 회원 가입 예외 처리
- 예외 발생 시 사용자에게 안내 메시지를 표시하며, 가능한 다음 동작을 안내하세요.
- 사용자의 입력 편의를 위해 이메일, 비밀번호의 유효성 검사를 실시간으로 제공해보세요.(TextWatcher, Regex Pattern등을 활용해 보세요)
1. TextWatcher
- EditText의 값이 변경될 때마다 값을 실시간으로 관찰하면서 입력 시점에 따라 이벤트를 주는 방법
- addTextChangedListener{} : EditText 문자 변경 시, 그 안에 들어 있는 함수에 맞춰서 실행
- beforeTextChanged : 텍스트 변경 전 호출
- onTextChanged : 텍스트 변경 중 호출
- afterTextChanged : 텍스트 변경 후 호출
- addTextChangedListener{} : EditText 문자 변경 시, 그 안에 들어 있는 함수에 맞춰서 실행
- 정규 표현식
- 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식 이름
- 전화번호, 주민번호, 이메일 등 사용자가 정해진 형식대로 입력했는지 검증해야 할 경우 사용
- [Android] 자바 코틀린 (Pattern, Matcher)정규식을 사용하여 패스워드 조건을 만들어보자 — IT Story (tistory.com)
[Android] 자바 코틀린 (Pattern, Matcher)정규식을 사용하여 패스워드 조건을 만들어보자
동아리 프로젝트 중, 비밀번호 변경을 구현하는 단계에서 정규식을 사용할 일이 생겼습니다. 조건은 '영문, 숫자, 특수문자 중 2개를 사용하여 최소 8자리 이상'의 비밀번호를 입력해야 합니다.
itstory1592.tistory.com
1-2. TextWatcher 사용법
① addTextChangedListener에 TextWatcher 인터페이스 연결
- 인터페이스이기 때문에 TextWatcher가 가지고 있는 메서드는 모두 구현
val signUpPw = findViewById<EditText>(R.id.signUpPw)
signUpPw.addTextChangedListener(object : TextWatcher{ //Ctrl+i
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
//비밀번호 유효성 검사 : 영문, 숫자, 특수문자 4~10자리
//양식에 맞지 않을 시 아래에 TextView로 확인 text 띄우기
}
})
② 정규식 표현을 담은 ragularPw() 메서드 만들기
- trim() : 문자열 앞뒤 공백 제거
- matches() : 문자열에서 원하는 패턴이 있는지 알아보는 매서드 (정규표현식 허용)
- ②-1 문제점 : 비밀번호 양식에 맞지 않을 시 textView로 text를 보여줄 예정. view의 보이는지 여부를 알 수 있는 활용 메서드 = isVisible
private fun ragularPw() {
val pwd = signUpPw.text.toString().trim()
val pwdPattern = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[\$@\$!%*#?&.])[A-Za-z[0-9]\$@\$!%*#?&.]{8,20}\$"
val pattern = Pattern.matches(pwdPattern, pwd)
if(pattern){
signUpPwText.isVisible = false
}else{
signUpPwText.isVisible = true
signUpPwText.text = getString(R.string.signUpPwmatch)
//양식에 맞지 않을 시 확인 text
}
}
③ SignUpActivity.kt
class SignUpActivity : AppCompatActivity() {
private lateinit var signUpPwText :TextView
private lateinit var signUpPw :EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_up)
val signUpButton = findViewById<Button>(R.id.signUpButton)
val signUpName = findViewById<EditText>(R.id.signUpName)
val inputUserName = signUpName.text.toString()
val signUpId = findViewById<EditText>(R.id.signUpID)
val inputUserId = signUpId.text.toString()
signUpPw = findViewById<EditText>(R.id.signUpPw)
val inputUserPw = signUpPw.text.toString()
signUpPwText = findViewById<TextView>(R.id.signUpPwText)
val isName = inputUserName.isEmpty()
val isId = inputUserId.isEmpty()
val isPw = inputUserPw.isEmpty()
signUpPw.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
ragularPw()
}
})
signUpButton.setOnClickListener {
if (isName || isId || isPw){
showToast("입력되지 않은 정보가 있습니다")
}
finish()
}
}
private fun showToast(message: String){
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun ragularPw() {
val pwd = signUpPw.text.toString().trim()
val pwdPattern = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[\$@\$!%*#?&.])[A-Za-z[0-9]\$@\$!%*#?&.]{8,20}\$"
val pattern = Pattern.matches(pwdPattern, pwd)
if(pattern){
signUpPwText.isVisible = false
}else{
signUpPwText.isVisible = true
signUpPwText.text = getString(R.string.signUpPwmatch)
}
}
}
3주차_ 소개글 앱 1. Intent + Toast msg (tistory.com)
3주차_ 소개글 앱 1. Intent + Toast msg
문제Lv1. [①] 새 프로젝트를 만들고 MainActivity의 이름을 SignInActivity로 바꿔주세요. [②] 로고 이미지는 원하는 이미지로 넣어주세요. [③] 아이디, 비밀번호를 입력 받는 EditText를 넣어주세요.(미리
hyelan-note.tistory.com
- ③-1 문제점 : ID만 치고 버튼을 누르면 Toast메시지만 띄어져야 하지만 로그인 화면도 같이 돌아감
- 반환값을 설정해 주지 않았음 = return@setOnClickListener
- ③-2 문제점 : 모두 작성 후(비어 있는 부분이 없음)에도 Toast메시지가 띄어짐
- val isName = inputUserName.isEmpty() 동작을 하여도 변수 선언 한 부분에서 true가 됨
- ③-3 문제점 : 모두 작성 후(비밀번호 유효성 검사 마침), 버튼을 눌러도 해당 페이지에 머물러 있음
- 인텐트를 걸어주지 않았음
④ SignUpActivity.kt (③ 문제점 해결)
더보기
class SignUpActivity : AppCompatActivity() {
private lateinit var signUpPwText :TextView
private lateinit var signUpPw :EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_up)
val signUpButton = findViewById<Button>(R.id.signUpButton)
val signUpName = findViewById<EditText>(R.id.signUpName)
val inputUserName = signUpName.text.toString()
val signUpId = findViewById<EditText>(R.id.signUpID)
val inputUserId = signUpId.text.toString()
signUpPw = findViewById(R.id.signUpPw)//lateinit 초기화
val inputUserPw = signUpPw.text.toString()
signUpPwText = findViewById(R.id.signUpPwText)//lateinit 초기화
signUpPw.addTextChangedListener(object : TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
regularPw()
}
})
signUpButton.setOnClickListener {
if (inputUserName.isEmpty() || inputUserId.isEmpty() || inputUserPw.isEmpty()){
showToast(getString(R.string.toastnotenter))
return@setOnClickListener
}
val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)
finish()
}
}
private fun showToast(message: String){
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun regularPw() {
val pwd = signUpPw.text.toString().trim()
val pwdPattern = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[\$@\$!%*#?&.])[A-Za-z[0-9]\$@\$!%*#?&.]{8,20}\$"
val pattern = Pattern.matches(pwdPattern, pwd)
Log.d("패턴","$pattern")
if(pattern){
signUpPwText.isVisible = false
}else{
signUpPwText.isVisible = true
signUpPwText.text = getString(R.string.signUpPwmatch)
}
}
}
- ④-1 문제점 : 비밀번호의 양식에 맞는 유무와 관련없이 화면전환
- regularPw()에 대한 true, false 을 조건문으로 삽입
- regularPw()의 반환값 필요
- ④-2 문제점 : if (inputUserName.isEmpty() || inputUserId.isEmpty() || inputUserPw.isEmpty()) 입력하는 시점이 공란이미로 해당 조건문에 걸리게 되어 창을 다 입력하여도 조건문에 걸리게 됨
- val inputUserName = signUpName.text.toString() 초기화 시점에 빈 값(text.toString())이 들어오게 되므로 if(signUpName.text.toString().isEmpty() ||...) 조건문 안에서 설정
class SignUpActivity : AppCompatActivity() {
private lateinit var signUpPwText: TextView
private lateinit var signUpPw: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_up)
val signUpButton = findViewById<Button>(R.id.signUpButton)
val signUpName = findViewById<EditText>(R.id.signUpName)
val signUpId = findViewById<EditText>(R.id.signUpID)
signUpPw = findViewById(R.id.signUpPw)
signUpPwText = findViewById(R.id.signUpPwText)
signUpPw.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
regularPw()
}
})
signUpButton.setOnClickListener {
if (signUpName.text.toString().isEmpty() || signUpId.text.toString().isEmpty() || signUpPw.text.toString().isEmpty()) {
showToast(getString(R.string.toastnotenter))
return@setOnClickListener
}
if (!regularPw()){
showToast(getString(R.string.signUpPwmatch))
return@setOnClickListener
}
val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)
finish()
}
}
private fun showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun regularPw():Boolean {
val pwd = signUpPw.text.toString().trim()
val pwdPattern =
"^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[\$@\$!%*#?&.])[A-Za-z[0-9]\$@\$!%*#?&.]{5,10}\$"
val pattern = Pattern.matches(pwdPattern, pwd)
if (pattern) {
signUpPwText.isVisible = false
return true//검사 결과 일때
} else {
signUpPwText.isVisible = true
signUpPwText.text = getString(R.string.signUpPwmatch)
return false
}
}
}
⑤ SignInActivity.kt
더보기
class SignInActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_in)
val signInButton = findViewById<Button>(R.id.signInButton)
val signUpButton = findViewById<Button>(R.id.signUpButton)
val userId = findViewById<EditText>(R.id.userId)
val userPw = findViewById<EditText>(R.id.userPw)
signUpButton.setOnClickListener {
val intent = Intent(this, SignUpActivity::class.java)
startActivity(intent)
}
signInButton.setOnClickListener {
if (userId.text.isEmpty()) {
showToast(getString(R.string.input_id))
return@setOnClickListener
}
if (userPw.text.isEmpty()) {
showToast(getString(R.string.input_pw))
return@setOnClickListener
}
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
private fun showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
동작화면
![]() |
![]() |
형식에 맞는 비밀번호 | 형식에 맞지 않은 비밀번호 |