-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1주차 과제] 안드로이드 UI 구현 기초 #2
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue에서 태스크를 정말 꼼꼼하게 나누셨네요!! 세밀한 To-do 작성을 기반으로 원자적 커밋을 할 수 있기 때문에 정말 좋은 습관인 것 같습니다 👏👏
code reformat 단축키(Window 기준 Ctrl + Alt + L)도 자주 눌러주시면 더 좋을 것 같아요!
코드 수정해주시고 reviewers에서 re-request 해주시면 달려올게요 💨
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
binding = ActivityLoginBinding.inflate(layoutInflater) | ||
setContentView(binding.root) | ||
|
||
// SharedPreferences에 저장된 유저 정보가 있으면 메인 화면으로 진입 | ||
if (isLastUserLoggedIn()) { | ||
navigateToMainScreen() | ||
} | ||
|
||
binding.root.setOnClickListener { | ||
hideKeyboard() | ||
} | ||
|
||
// 회원가입 화면으로부터 유저 정보 가져오기 | ||
resultLauncher = registerForActivityResult( | ||
ActivityResultContracts.StartActivityForResult() | ||
) { result -> | ||
if (result.resultCode == RESULT_OK) { | ||
Snackbar.make(binding.root, SIGN_UP_SUCCESS_MSG, Snackbar.LENGTH_SHORT).show() | ||
registerUserInfo(result.data) | ||
|
||
// 자동 로그인을 위해 SharedPreferences에 유저 정보 저장하기 | ||
saveUserInfoToPrefs() | ||
} | ||
} | ||
|
||
binding.btnLogin.setOnClickListener { | ||
if (userRegisteredStatus) { | ||
if (checkInputValues()) { | ||
Toast.makeText(this, LOGIN_SUCCESS_MSG, Toast.LENGTH_SHORT).show() | ||
navigateToMainScreen() | ||
} else { | ||
Toast.makeText(this, LOGIN_FAIL_MSG, Toast.LENGTH_SHORT).show() | ||
} | ||
} else { | ||
Toast.makeText(this, NOT_YET_REGISTERED_MSG, Toast.LENGTH_SHORT).show() | ||
} | ||
} | ||
|
||
binding.btnSignUp.setOnClickListener { | ||
val intent = Intent(this, SignUpActivity::class.java) | ||
resultLauncher.launch(intent) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onCreate()
함수에 로직이 몰려 있는 것 같습니다!
함수화를 통해 로직을 분리해주시면 가독성도 좋아지고 onCreate의 역할을 덜어줄 수 있어 좋을 것 같습니다 🙃
Toast.makeText(this, LOGIN_SUCCESS_MSG, Toast.LENGTH_SHORT).show() | ||
navigateToMainScreen() | ||
} else { | ||
Toast.makeText(this, LOGIN_FAIL_MSG, Toast.LENGTH_SHORT).show() | ||
} | ||
} else { | ||
Toast.makeText(this, NOT_YET_REGISTERED_MSG, Toast.LENGTH_SHORT).show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스낵바나 토스트를 발생시키는 함수는 프로젝트 전역에서 재사용될 수 있기 때문에 Activity나 Context, View의 확장함수를 사용하는 방법을 찾아보셔도 좋을 것 같습니다 :)
확장 함수 한번 만들어놓으면 코드량을 엄청 줄일 수 있기 때문에 굉장히 편리합니다!
val intent = Intent(this, MainActivity::class.java) | ||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) | ||
startActivity(intent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val intent = Intent(this, MainActivity::class.java) | |
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) | |
startActivity(intent) | |
Intent(this, MainActivity::class.java).apply { | |
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) | |
startActivity(this) | |
} |
스코프 함수 apply
나 also
를 활용하여 코틀린스럽게 작성할 수도 있습니다 ㅎㅎ
binding.tvName.text = "이름: $name" | ||
binding.tvHobby.text = "특기: $hobby" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
binding.tvName.text = "이름: $name" | |
binding.tvHobby.text = "특기: $hobby" | |
binding.tvName.append(name) | |
binding.tvHobby.append(hobby) |
append()
함수를 활용하여 좀 더 간결하게 작성할 수도 있습니다!
private fun getAllInputValues(): List<String> { | ||
val id = binding.etId.text.toString() | ||
val pw = binding.etPw.text.toString() | ||
val name = binding.etName.text.toString() | ||
val hobby = binding.etHobby.text.toString() | ||
return listOf(id, pw, name, hobby) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private fun getAllInputValues(): List<String> { | |
val id = binding.etId.text.toString() | |
val pw = binding.etPw.text.toString() | |
val name = binding.etName.text.toString() | |
val hobby = binding.etHobby.text.toString() | |
return listOf(id, pw, name, hobby) | |
} | |
private fun getAllInputValues(): User { | |
val id = binding.etId.text.toString() | |
val pw = binding.etPw.text.toString() | |
val name = binding.etName.text.toString() | |
val hobby = binding.etHobby.text.toString() | |
return User(id, pw, name, hobby) | |
} |
Data Class로 정의하신 User 클래스를 활용해보는 건 어떨까요?
private fun checkLengthOfId(id: String): Boolean { | ||
return id.length in ID_MIN_LEN..ID_MAX_LEN | ||
} | ||
|
||
private fun checkLengthOfPw(pw: String): Boolean { | ||
return pw.length in PW_MIN_LEN..PW_MAX_LEN | ||
} | ||
|
||
companion object { | ||
private const val ID_MIN_LEN = 6 | ||
private const val ID_MAX_LEN = 10 | ||
private const val PW_MIN_LEN = 8 | ||
private const val PW_MAX_LEN = 12 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상수 관리 꼼꼼하게 잘 하셨네요!! 👍👍
const val SIGN_UP_SUCCESS_MSG = "회원가입이 완료되었습니다." | ||
const val LOGIN_SUCCESS_MSG = "로그인에 성공했습니다." | ||
const val LOGIN_FAIL_MSG = "등록된 유저 정보가 없습니다." | ||
const val NOT_YET_REGISTERED_MSG = "회원가입을 먼저 진행해주세요." | ||
const val INVALID_INPUT_ERROR = "모든 항목에 유효한 값을 입력해주세요." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UI에 표시되는 메시지 문자열들은 strings.xml에서 정의하여 사용하는 것이 리소스 사용량을 줄이고 유지보수가 용이할 것 같습니다!
앱을 국제화하기 위해 다른 언어로 번역하여 지원하게 될 경우에도 편리할 것입니다 :)
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:layout_marginTop="20dp" | ||
android:text="Welcome to GO Android!" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
귀찮긴 하지만 xml에서도 텍스트 추출로 보일러플레이트를 줄여봅시다!
android:text="Hello World!" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintEnd_toEndOf="parent" | ||
tools:text="이름: " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위에서 설명드린 append 함수를 활용하게 된다면 android:text
속성을 활용하시면 될 것 같습니다!
<color name="black">#FF000000</color> | ||
<color name="white">#FFFFFFFF</color> | ||
<color name="red">#F44336</color> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
color까지 지정하시다니 👍👍
3주차 세미나 때 팟짱님이 알려주시겠지만 네이밍을 하실 때 Material Design을 참고하셔도 좋을 것 같아요 😉
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { | ||
} | ||
|
||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addTextChangedListener를 활용해 길이제한조건을 사용자에게 명시해주는 점 좋았습니다 😘
return id.length in 6..10 | ||
} | ||
|
||
private fun checkValidityOfPw(pw: String): Boolean { | ||
private fun checkLengthOfPw(pw: String): Boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
함수명이 항상 기능을 직관적으로 잘명시되어있는 것 같습니다 ! 참고해야겠어용
binding.btnLogin.setOnClickListener { | ||
if (userRegisteredStatus) { | ||
if (checkInputValues()) { | ||
Toast.makeText(this, LOGIN_SUCCESS_MSG, Toast.LENGTH_SHORT).show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
토스트 메시지 분리 해도 될거 같아요!
return id != null && pw != null && name != null && hobby != null | ||
} | ||
|
||
private fun hideKeyboard() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이기능도 util로 빼면 좋을거 같네요 !
binding.etId.addTextChangedListener { | ||
if (!checkLengthOfId(it.toString())) { | ||
binding.tvIdLimitError.visibility = View.VISIBLE | ||
} else { | ||
binding.tvIdLimitError.visibility = View.INVISIBLE | ||
} | ||
} | ||
|
||
binding.etPw.addTextChangedListener { | ||
if (!checkLengthOfPw(it.toString())) { | ||
binding.tvPwLimitError.visibility = View.VISIBLE | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
에러체크까지 꼼꼼하시네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
필수 과제
심화 과제
도전 과제
실행 결과