본문 바로가기
개발노트/Kotlin

4주차 3일차 안드로이드 입문 과제 기능구현 완

by 시계속세상은아직돌아가는중 2023. 8. 2.

https://github.com/S4U2M/Android_Beginner_Assignment

 

GitHub - S4U2M/Android_Beginner_Assignment

Contribute to S4U2M/Android_Beginner_Assignment development by creating an account on GitHub.

github.com

1. 고안

 

과제를 진행하면서 주어진 것은

 

1. 로그인 페이지

2. 회원가입 페이지

3. 자기소개 페이지

 

형식은 자유

 

였다. 이에 갑자기 내가 평소에 좋아하는 건담이 떠올라 건담의 파일럿을 작성하는 형식으로 하면 재밌지 않을까? 라는 아이디어에서 시작되었다.

 

2. 구현

 

1)로그인 페이지

 

로그인 페이지는 하나의 ConstraintLayout으로 구성되어있으며, 각 관계를 지정해 최대한 같은 간격과 깔끔하게 보이도록 노력했다. 

 

class SignInActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign)
        val signB = findViewById<Button>(R.id.sign)

        signB.setOnClickListener {
            val moveToSign = Intent(this, SignupActivity::class.java)
            startActivity(moveToSign)
        }
    }

    fun login(view: View) {
        val id = findViewById<EditText>(R.id.id_Edit)
        val psw = findViewById<EditText>(R.id.psw_Edit)

        val inputId = id.text.toString()
        val inputPsw = psw.text.toString()

        val userFindInfo = UserManager.userList.find { it.id == inputId && it.password == inputPsw }

        if (userFindInfo != null) {

            val moveToHome = Intent(this, HomeActivity::class.java)
            Toast.makeText(this, "로그인이 성공하였습니다", Toast.LENGTH_SHORT).show()

            val bundle = Bundle()

            bundle.putSerializable("loginUserInfo",userFindInfo)
            moveToHome.putExtra("bundle",bundle)

            startActivity(moveToHome)

        } else {
            Toast.makeText(
                this,
                "로그인에 실패하였습니다.\n" +
                        "아이디와 비밀번호를 확인해주세요.", Toast.LENGTH_LONG
            ).show()
        }
    }
    
}

회원가입 페이지로 이동하는 것은 간단하게 구현이 가능하기 때문에 id를 불러와 setOnClickListener를 사용해 해동 페이지로 이동하도록 구성하였다.

 

하지만, 로그인을 완성시키는 것을 구현하기에는 따로 함수를 만들어 onClick으로 지정해주는 것이 좋을 것 같았다.

코드가 길어질수록 해당 생각은 잘했다고 생각했다.

 

data class User(val id:String, val password:String, val name:String,
val age:String, var gender:String, var MBTI:String,var hobby:String) :
    Serializable

object UserManager {

    var userList:ArrayList<User> = ArrayList()

    init {
        userList.add(User("test","test","테스트중","10","건담","IFIF","알렐루야 할렐루야!" ))
    }

}

먼저 해당 코드를 이해하기 전에 로그인자의 정보를 저장한 부분이다.

object를 사용해 이것이 어디에 사용되든 바로 여기에 접근할 수 있도록 구현하였는데, 이는 클래스로 구현 시 다른 액티비티에서 관여하기 힘들어지기 때문이었다.

 

최초에 class로 만들었을 당시에는 회원가입이 정상작동하나, userList안에 직접적으로 들어가지 않았었다.

 

val id = findViewById<EditText>(R.id.id_Edit)
val psw = findViewById<EditText>(R.id.psw_Edit)

val inputId = id.text.toString()
val inputPsw = psw.text.toString()

부분은 EditText에 적혀있는 문자들을 toStirng형태로 받아내는 부분이다.

 

이렇게 받은 변수를

 

val userFindInfo = UserManager.userList.find { it.id == inputId && it.password == inputPsw }

 

오브젝트 UserManager의 userList속을 find 해준다.

EditText에 입력된 id와 password가 같은 객체가 있다면 그 객체를 반환해줄 것이고 없다면 null을 반환해주는 형식이다.

즉 null반환 = 로그인 실패가 되는 것 이다.

if (userFindInfo != null)

따라서 userfindInfo가 != null 즉 null이 아닐 때

Toast.makeText(this, "로그인이 성공하였습니다", Toast.LENGTH_SHORT).show()

'로그인에 성공하였습니다'.라는 토스트 메세지를 띄운 뒤

val bundle = Bundle()

bundle.putSerializable("loginUserInfo",userFindInfo)
moveToHome.putExtra("bundle",bundle)

userFindInfo를 bundle형태로 만들어 putExtra로 넘길 수 있게 해준다.

 

putExtra는 객체를 바로 넘길 수 없으므로 

bundle.putSerializable("loginUserInfo",userFindInfo)

를 사용해 userfindInfo를 putExtra로 넘길 수 있는 형태로 만들어낸다.

 

그 후

val moveToHome = Intent(this, HomeActivity::class.java)
.
.
.
코드
.
.
startActivity(moveToHome)

그 후 home화면 즉 프로필 화면 구성에 필요한 모든 데이터를 넘긴 뒤 홈 화면으로 이동하게 된다.

 

else {
    Toast.makeText(
        this,
        "로그인에 실패하였습니다.\n" +
                "아이디와 비밀번호를 확인해주세요.", Toast.LENGTH_LONG
    ).show()
}

else 즉 findUserInfo가 null이라면 로그인 실패 메시지를 띄운다.

 

2) 회원가입 페이지

 

회원가입 페이지는 전체를 스크롤뷰로 해서 스크롤 할 수 있도록 만들고

constrainLayout을 통한 타이틀과 로그를 띄운 뒤

LinearLayout을 사용해 아래 정보 구성을 하도록 만들었다.

 

여기서 재밌는건 아래 버튼으로 이 버튼은 constrainLayout의 위젯이다.

이는

app:layout_constraintTop_toBottomOf="@+id/linear"

linearLayout의 id를 지정한 뒤 constrain을 지정해서 배치한 모습이다.

버튼 아래의 여백을 주기 위해서 space위젯을 활용하였다.

 

어제 마구잡이로 배치한 constrain위젯을 열심히 정렬하려는 노력보다, 그 부분을 전부 LinearLayout으로 배치하자 똑같은 간격과 위치를 주기 더 쉬워졌다. constrainLayout은 조금만 건드리면 다른 위젯들관의 관계가 꼬여서 그렇게 하기 힘들었는데 말이다.

 

package com.example.android_beginner_assginment

import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.core.content.ContextCompat

class SignupActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_signup)

    }

    fun signupfinish(view: View) {

        val id = findViewById<EditText>(R.id.id_create)
        val psw = findViewById<EditText>(R.id.psw_create)
        val name = findViewById<EditText>(R.id.name_create)
        val age = findViewById<EditText>(R.id.age_create)
        val gender = findViewById<EditText>(R.id.gender_create)
        val mbti = findViewById<EditText>(R.id.mbti_create)
        val hobby = findViewById<EditText>(R.id.hobby_create)

        val inputId = id.text.toString()
        val inputpsw = psw.text.toString()
        val inputname = name.text.toString()
        val inputage = age.text.toString()
        val inputgender = gender.text.toString()
        val inputmbti = mbti.text.toString()
        val inputhobby = hobby.text.toString()

        if (inputId.isEmpty() || inputpsw.isEmpty() || inputname.isEmpty()
            || inputId.isEmpty() || inputgender.isEmpty() || inputmbti.isEmpty() || inputhobby.isEmpty()
        ) {

            Toast.makeText(this, "공백을 채워주세요", Toast.LENGTH_SHORT).show()
            Changingcolors(
                id = id,
                inputId = inputId,
                psw = psw,
                inputpsw = inputpsw,
                name = name,
                inputname = inputname,
                inputage = inputage,
                age = age,
                inputgender = inputgender,
                gender = gender,
                inputmbti = inputmbti,
                mbti = mbti,
                inpuhobby = inputhobby,
                hobby = hobby
            )

        } else {

            if (UserManager.userList.find { it.id == inputId } == null) {

                UserManager.userList.add(
                    User(
                        inputId,
                        inputpsw,
                        inputname,
                        inputage,
                        inputgender,
                        inputmbti,
                        inputhobby
                    )
                )
                finish()

            } else {

                beRed(id)
                beWhite(psw)
                beWhite(name)
                beWhite(age)
                beWhite(gender)
                beWhite(mbti)
                beWhite(hobby)

                Toast.makeText(this, "중복된 아이디는 생성할 수 없습니다.\n 다시 입력해주세요", Toast.LENGTH_SHORT)
                    .show()
            }

        }
    }

    fun Changingcolors(
        inputId: String, id: View,
        inputpsw: String, psw: View,
        inputname: String, name: View,
        inputage: String, age: View,
        inputgender: String, gender: View,
        inputmbti: String, mbti: View,
        inpuhobby: String, hobby: View
    ) {

        if (inputId.isEmpty()) {
            beRed(id)
        } else {
            beWhite(id)
        }

        if (inputpsw.isEmpty()) {
            beRed(psw)
        } else {
            beWhite(psw)
        }

        if (inputname.isEmpty()) {
            beRed(name)
        } else {
            beWhite(name)
        }

        if (inputage.isEmpty()) {
            beRed(age)
        } else {
            beWhite(age)
        }

        if (inputgender.isEmpty()) {
            beRed(gender)
        } else {
            beWhite(gender)
        }

        if (inputmbti.isEmpty()) {
            beRed(mbti)
        } else {
            beWhite(mbti)
        }

        if (inpuhobby.isEmpty()) {
            beRed(hobby)
        } else {
            beWhite(hobby)
        }
    }

    fun beRed(id: View) {
        id.setBackgroundColor(ContextCompat.getColor(this, android.R.color.holo_red_light))
    }

    fun beWhite(id: View) {
        id.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white))
    }

}

해당 부분은 어려운 부분은 아니지만, 자기 소개에 이름만 넣기에는 너무 휑해서 여러가지를 넣다보니 복잡해보일 뿐이다.

 

로그인 페이지처럼 각 EditText를 string형태의 변수로 지정한 뒤

if (inputId.isEmpty() || inputpsw.isEmpty() || inputname.isEmpty()
    || inputId.isEmpty() || inputgender.isEmpty() || inputmbti.isEmpty() || inputhobby.isEmpty()
) 

EditText부분이 비여있다면 

Toast.makeText(this, "공백을 채워주세요", Toast.LENGTH_SHORT).show()

공백을 띄운 

Changingcolors()

함수를 이용해 빈 공간을 붉은색으로 하이라이트해준다.

 

해당 안에 들어있는 변수들은 순서대로 입력한다면 문제가 없겠지만,

각각 변수에 알맞는 변수를 실수없이 넣어주기 위해 함수의 인자 = 변수명으로 넣어주었다.

 

해당 함수도 어려울 것 없이

 

   fun beRed(id: View) {
        id.setBackgroundColor(ContextCompat.getColor(this, android.R.color.holo_red_light))
    }

    fun beWhite(id: View) {
        id.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white))
    }
  
    fun Changingcolors(인자들){
    
   if (inputId.isEmpty()) {
            beRed(id)
        } else {
            beWhite(id)
        }
        .
        .
        .
   }

만약 각 인자가 비여있다면 해당 인자를 받아온 id를 체크해 그 부분을 흰색 혹은 붉은색으로 바꿔주는 함수이다.

 

만약 비여있는 부분이 없다면

 

if (UserManager.userList.find { it.id == inputId } == null) {

                UserManager.userList.add(
                    User(
                        inputId,
                        inputpsw,
                        inputname,
                        inputage,
                        inputgender,
                        inputmbti,
                        inputhobby
                    )
                )
                finish()

            } else {

                beRed(id)
                beWhite(psw)
                beWhite(name)
                beWhite(age)
                beWhite(gender)
                beWhite(mbti)
                beWhite(hobby)

                Toast.makeText(this, "중복된 아이디는 생성할 수 없습니다.\n 다시 입력해주세요", Toast.LENGTH_SHORT)
                    .show()
            }

id가 겹치는지 확인한 뒤 겹친다면 User형태의 객체로 만들어 리스트에 추가하고

아니면 id부분을 붉은색으로 하이라이트해서 표시한 뒤 토스트 문구를 띄운다.

 

User객체 생성에 대응되는 변수의 순서를 잘못주게 된다면 잘못된 값이 전달될 수 있기에 이 부분도 id = inputId로 작성하는 것이 좋을 것이다. 실제로도 처음에는 그렇게 작성했었다.

 

그 부분을 지운 이유는 복잡해보여서였는데, 다시 생각해보니 롤백할 필요가 있는 것 같다.

 

3) 프로필화면

프로필 화면의 레이아웃은 회원가입 화면의 레이아웃과 구성이 동일하다.

 

class HomeActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        val receivedIntent = intent
        val receivedBundle = receivedIntent.getBundleExtra("bundle")

        val name = findViewById<TextView>(R.id.nameInprfile)
        val age = findViewById<TextView>(R.id.ageInprofile)
        val gender = findViewById<TextView>(R.id.genderInprofile)
        val mbti = findViewById<TextView>(R.id.mbtiInprofile)
        val hobby = findViewById<TextView>(R.id.hobbyInprofile)

        val user = receivedBundle?.getSerializable("loginUserInfo") as User

            name.text = " ${user.name}"
            age.text = "${user.age}"
            gender.text = "${user.gender}"
            mbti.text = "${user.MBTI}"
            hobby.text = "${user.hobby}"

    }


}

 

여기서 눈여겨 봐야할 것은 데이터를 전달받은 방식이다.

val receivedIntent = intent
val receivedBundle = receivedIntent.getBundleExtra("bundle")

 

 

receivedIntent 라는 변수를 선언해 번들을 받아올 준비를 한 뒤

receivedBundle 변수를 통해 bundle key값을 받아 해당 정보를 받아온다

받아온 번들은 User객체를 전달을 위해 형태를 변환시켰으므로 다시 Uesr형태로 변환시켜줄 필요가 있다.

 

따라서

val user = receivedBundle?.getSerializable("loginUserInfo") as User

receivedBundle이 null이 아님을 체크해주고 변환된 정보의 key값을 입력한 뒤 as User 즉 User형태로 만들어준다.

 

이후에는 텍스트 뷰의 id를 받아온 뒤 각 변환한 정보들을 textview에다가 넣어주는 형태이다.

 

name.text = " ${user.name}"
age.text = "${user.age}"
gender.text = "${user.gender}"
mbti.text = "${user.MBTI}"
hobby.text = "${user.hobby}"

 

 

3. 이후에 할 것들

 

현재 구현한 것은 과제의 lv.3까지의 구현이다. 그렇다면 이후 추가 구현사항을 구현해야하지 않을까?

그리고 더 나아가 현재 배운 범위 내에서 어떤 기능들을 넣을 수 있을까에 대한 고민도 할 필요가 있어보인다.

 

현재 빈 공간 하이라이트는 onClick으로 지정되어 있어 버튼이 눌려야만 수행되는 방식인데, 이를 조금 수정해서 각 EdixText가 비여있는지 여부를 판단한 뒤 색을 바꾸는 형식도 도입하면 어떨까 싶다.

 

이미 클릭으로 색이 변했으므로, EditText가 isempty있는지 판단하여 비여있지 않다면 흰색으로 바꾸는 방식도 고민해볼만 하다 생각하다.

 

 

 

참고 유튜브/유튜브

https://www.youtube.com/watch?v=RImYXqZJsnE

https://gakari.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9C%84%EC%A0%AF%EC%9D%98-%EB%B0%B0%EC%B9%98%EB%A5%BC-%ED%8E%B8%EB%A6%AC%ED%95%98%EA%B2%8C-%ED%95%B4%EC%A3%BC%EB%8A%94-Space-%EC%9C%84%EC%A0%AF

 

안드로이드 - 위젯의 배치를 편리하게 해주는 Space 위젯

Space 위젯은 말그대로 공간만 차지하는 위젯이다. 이러한 단순한 위젯을 활용하면 내가 원하는 곳에 위젯을 배치하는데 편리하게 이용할 수 있다. 예제는 매우 간단하다. xml파일 activity_space_test.x

gakari.tistory.com

https://recipes4dev.tistory.com/56

 

텍스트뷰 기본 사용법. (Android TextView)

1. 안드로이드 TextView TextView는 안드로이드 UI를 구성함에 있어 화면에 텍스트를 표시하는 기능을 담당하며, 안드로이드에서 제공하는 위젯 중 가장 많이 사용되는 위젯입니다. 텍스트 출력 기능

recipes4dev.tistory.com

https://kotlinworld.com/45

 

[Bundle] Android Bundle 이란 무엇인가? Bundle을 이용해 데이터 전달하기

목표 Bundle이 가진 특성을 이해한다. Bundle에 어떤 객체가 들어가고 나올 수 있는지 안다. Bundle Bundle이란 Map형태로 구현된 데이터의 묶음(Bundle)이다. Map형태라 key 값이 String이며, value값에는 Int, Str

kotlinworld.com

https://www.crocus.co.kr/1560

 

Android Bundle이란?

Bundle이란? Bundle은 여러가지의 타입의 값을 저장하는 Map 클래스이다. 예를 들면 string 값을 Bundle 클래스에 Mapping(대응, 변환)하는 것이다. 기본타입인 int, double, long, String 부터 FloatArray, StringArrayList

www.crocus.co.kr

오늘 푼 문제

https://clockstillticktockticktock.tistory.com/30

 

프로그래머스 숫자찾기 코틀린

https://school.programmers.co.kr/learn/courses/30/lessons/120904 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞

clockstillticktockticktock.tistory.com