ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TECHIT 앱 스쿨 2기: Android 31일차 (23.06.12)
    [THEC!T] 앱 스쿨2기 : Android 2023. 6. 12. 23:59
    728x90

    자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용

     

    오늘의 시작은 지난주에 내주신 과제에 대한 설명과 작성으로 시작하였습니다.

    강사님께서 작성하신 코드와 제가 작성한 코드의 차이점은 학생정보 데이터 클래스에서 취미를 추가하는 함수를 만드신 뒤에 리스트에 저장하신 후 추후 리스트에서 뽑아 출력하는 형태로 작성하셨었다는 점이 가장 큰 차이점이였던 것 같습니다.

     

    이후로는 view visibility 에 대해서 설명을 해주셨습니다.

    간단하게 말하자면 

     

    visible : 눈에 보이며 뷰 내에서 공간을 차지하고 있는 상태

    invisible : 눈에 보이지는 않지만 뷰 내에서 공간을 차지하고 있는 상태

    gone : 눈에 보이지 않으며 뷰 내에서도 공간을 차지하고 있지 않는 상태

     

    그리고 지금까지 배운 내용과 view visibility 를 이용하여 작성할 수 있는 문제를 내주셨습니다.

    생각보다 간단할 줄 알았는데 제가 원하는 기능이 나오지 않아 시간이 좀 많이 걸렸습니다.

     

    문제는 하기와 같습니다.

    저의 경우 엔터키를 누르면 키보드가 사라지는 것을 구현하고 싶었는데 해당 기능이 포커스 중심이라 제 생각대로 되지 않아 골치가 아팠습니다. 저의 경우 마지막 입력값을 입력 후 엔터키를 누르면 해당 포커스에서 키보드가 사라질 줄 알았는데 원하는 대로 키보드가 사라지지 않아 포커스 흐름을 따라가 봤으나 처음에는 계속 실패를 했습니다.

    하지만 계속 분석을 하다보니 라디오 버튼 관련 코드에서 포커스를 호출하여 진행되는 것 같아 해당 코드를 일부 수정을 하였더니 제가 원하는 기능이 나와 왜? 라는 질문이 스스로에 들었던 것 같습니다. 

    해당 코드는 강사님께 여쭤보면서 한번 물어봐야 할 것 같습니다.

    해당문제는 강사님과 함께 작성하는 문제가 아니기 때문에 제가 아직 안드로이드에 대해서 특히 제 예상으로는 생명주기와 일부 관련이 있지 않을까? 라는 생각이 듭니다. 혹은 함수에 작동 원리를 잘 몰랐거나 등등 내일 질문을 할 생각입니다.

     

    동물원
    
    동물의 타입을 라디오 버튼으로 선택한다.
    동물은 코끼리, 고양이, 강아지이다.
    
    코끼리
    동물 종류 : 코끼리
    먹이 : 나뭇잎
    추가 입력
    이름 : 
    코의길이 : 
    
    고양이
    동물 종류 : 고양이
    먹이 : 고양이 사료
    추가 입력
    이름 :
    냥펀치 속도 :
    
    강아지
    동물 종류 : 강아지
    먹이 : 강아지 사료
    추가 입력
    이름 :
    개인기 개수 : 
    
    버튼을 누르면
    다음과 같이 출력한다.
    
    코끼리 : 00마리
    고양이 : 00마리
    강아지 : 00마리
    
    동물들의 정보를 모두 출력한다.

    하기는 제가 작성한 코드 입니다.

    package com.test.android_study_zoo
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.view.inputmethod.InputMethodManager
    import androidx.core.view.isVisible
    import com.test.android_study_zoo.databinding.ActivityMainBinding
    
    class MainActivity : AppCompatActivity() {
    
        lateinit var activityMainBinding : ActivityMainBinding
        lateinit var imm : InputMethodManager
    
        val animalList = ArrayList<Animal>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(activityMainBinding.root)
    
            activityMainBinding.run{
    
    
                // 선택된 그룹에 따라 리니어 레이아웃 표시
                animalGroup.run{
                    setOnCheckedChangeListener { group, checkedId ->
                        when(checkedId){
                            // 코끼리가 선택된 경우
                            radioButtonElephant.id ->{
                                // 화면 숨기기
                                LinearLayoutElephant.isVisible = true
                                LinearLayoutCat.isVisible = false
                                LinearLayoutDog.isVisible = false
    
                                // 포커스 가져오기
                                editTextElephantName.run{
                                    requestFocus()
                                    imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                                    imm.showSoftInput(currentFocus,0)
                                }
    
                            }
                            // 고양이가 선택된 경우
                            radioButtonCat.id ->{
                                LinearLayoutElephant.isVisible = false
                                LinearLayoutCat.isVisible = true
                                LinearLayoutDog.isVisible = false
    
                                // 포커스 가져오기
                                editTextCatName.run{
                                    requestFocus()
                                    imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                                    imm.showSoftInput(currentFocus,0)
                                }
    
                            }
                            // 강아지가 선택된 경우
                            radioButtonDog.id ->{
                                LinearLayoutElephant.isVisible = false
                                LinearLayoutCat.isVisible = false
                                LinearLayoutDog.isVisible = true
    
                                // 포커스 가져오기
                                editTextDogName.run{
                                    requestFocus()
                                    imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                                    imm.showSoftInput(currentFocus,0)
                                }
    
                            }
                            // 아무것도 선택되지 않은 경우
                            else -> {
                                if(currentFocus != null){
                                    imm.hideSoftInputFromWindow(currentFocus!!.windowToken,0)
                                    currentFocus!!.clearFocus()
                                }
                                LinearLayoutElephant.isVisible = false
                                LinearLayoutCat.isVisible = false
                                LinearLayoutDog.isVisible = false
    
                            }
                        }
                    }
                }
    
                // 코 길이 입력 후 엔터키
    
                editTextElephantNoseLength.setOnEditorActionListener { v, actionId, event ->
                    animalList.add(Elephant("코끼리","나뭇잎",editTextElephantName.text.toString(),editTextElephantNoseLength.text.toString()))
    
                    if(currentFocus != null){
                        imm.hideSoftInputFromWindow(currentFocus!!.windowToken,0)
                        currentFocus!!.clearFocus()
                    }
    
                    editTextElephantName.text.clear()
                    editTextElephantNoseLength.text.clear()
                    animalGroup.clearCheck()
    
                    false
                }
    
                // 냥 펀치 입력 후 엔터키
                editTextCatPunchSpeed.setOnEditorActionListener { v, actionId, event ->
                    animalList.add(Cat("고양이","고양이 사료",editTextCatName.text.toString(),editTextCatPunchSpeed.text.toString()))
                    if(currentFocus != null){
                        imm.hideSoftInputFromWindow(currentFocus!!.windowToken,0)
                        currentFocus!!.clearFocus()
                    }
    
                    editTextCatName.text.clear()
                    editTextCatPunchSpeed.text.clear()
                    animalGroup.clearCheck()
    
                    false
                }
    
                // 개인기 개수 입력 후 엔터키
                editTextDogPerforCount.setOnEditorActionListener { v, actionId, event ->
                    animalList.add(Dog("강아지","강아지 사료", editTextDogName.text.toString(), editTextDogPerforCount.text.toString()))
    
                    if(currentFocus != null){
                        imm.hideSoftInputFromWindow(currentFocus!!.windowToken,0)
                        currentFocus!!.clearFocus()
                    }
    
                    editTextCatName.text.clear()
                    editTextCatPunchSpeed.text.clear()
                    animalGroup.clearCheck()
    
                    false
                }
    
                // 동물 정보 출력 버튼 클릭 시
                ButtonPrintInfo.run{
                    setOnClickListener {
    
                        if(currentFocus != null){
                            imm.hideSoftInputFromWindow(currentFocus!!.windowToken,0)
                            currentFocus!!.clearFocus()
                        }
    
                        textViewPrintInfo.text = ""
    
                        val elephantCount = animalList.count{ it is Elephant}
                        val catCount = animalList.count{ it is Cat}
                        val dogCount = animalList.count{ it is Dog}
    
                        textViewPrintInfo.append("코끼리 : ${elephantCount}마리\n")
                        textViewPrintInfo.append("고양이 : ${catCount}마리\n")
                        textViewPrintInfo.append("강아지 : ${dogCount}마리\n")
                        textViewPrintInfo.append("\n")
    
                        for(animal in animalList){
                            textViewPrintInfo.append("${animal.returnInfo()}\n")
                            textViewPrintInfo.append("\n")
                        }
    
                    }
                }
    
            }
    
        }
    }

    실행화면

    시작화면

     

    라디오 버튼에서 동물 선택
    정보 입력 후 엔터를 누른 뒤

    지금 봤는데 코끼리에 저게 뭐죠...? 질문거리가 늘어났습니다ㅋㅋㅋㅋㅋ

    동물 정보 출력 버튼을 클릭 후

    출력 및 저장은 다 되었으나 키보드가 맘에 안들어 수정이 오래 걸렸던 문제 인 것 같습니다.

     

     

    다시 수업이야기로 돌아오자면 이후로는 개발자가 커스텀을 할 수 있는 커스텀 뷰에 대해서 학습하였습니다.

    기본적인 내용으로는 하기와 같습니다.

     

    [ToggleButton]
    textOff : Off 상태일 때 표시하는 문자열
    textOn : On 상태일 때 표시하는 문자열

    [Switch]
    text : 좌측에 나타나는 문자열
    textOn : ON 상태일 때 표시할 문자열
    textOff : OFF 상태일 때 표시할 문자열
    showText : textOn, TextOff 에 설정할 문자열을 보여줄 것인가
    thumb : 버튼 이미지
    track : 트랙 이미지

    [CheckedTextView]
    clickable : 터치에 대해 반응하도록 설정한다.
    text : 표시할 문자열
    checkMark : 체크할 이미지
    drawableLeft : 좌측에 표시할 이미지
    drawableRight : 우측에 표시할 이미지
    drawableTop : 상단에 표시할 이미지
    drawableBottom : 하단에 표시할 이미지

    [Chip]
    style : chip의 모양을 설정한다. 생략시 Action, Chice, Entry, Filter ...
    Checkable : 체크 가능여부
    Text : 표시할 문자열
    Chipicon : chip에 표시할 아이콘
    chipIconVisible : chip 아이콘을 표시할 것인가
    checkedIcon : 선택되었을 때의 아이콘
    checkedIconVisible : 선택되었을 때의 아이콘을 표시 여부

    [ChipGroup]
    singleSelection : 하나만 선택되게 할 것 인가
    checkedChip : 시작할 때 선택되어 있을 chip 선택

    [ProgressBar]
    style : 모양. 크기 혹은 bar 형태
    max : 최대 값
    progress : 현재 값

    [SeekBar]
    style : 모양. 크기 혹은 bar 형태
    max : 최대 값
    progress : 현재 값

    [RatingBar]
    style : 모양(크기가 조절된다)
    numStarts : 별의 개수
    rating : 현재 값
    stepSize : 설정할 별 값 단위
    isIndicator : 사용자 설정 가능 여부

     

    배운 것들을 사용하여 문제를 내주셨고 문제를 작성하며 오늘의 강의는 종료 되었습니다.

    해당 뷰 또한 제가 원하는대로 사용하지 못한 특성이 있는데 바로 Chip 입니다.

    Chip의 속성에 대한 이해가 부족했는지 제가 원하는대로 되지 않아 임시방편으로 다르게 구분을 하였습니다.

     

    문제는 하기와 같습니다.

     

    제가 작성한 코드입니다.

    package com.test.android25_homeworkmovie
    
    import android.graphics.Color
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.os.SystemClock
    import android.view.inputmethod.InputMethodManager
    import android.widget.SeekBar
    import com.test.android25_homeworkmovie.databinding.ActivityMainBinding
    import kotlin.concurrent.thread
    
    class MainActivity : AppCompatActivity() {
    
        lateinit var activityMainBinding: ActivityMainBinding
        lateinit var imm : InputMethodManager
    
        val movieList = ArrayList<Movie>()
    
        data class Movie(val movieName: String, val mdName: String, val price: Int, val lookAge: String, val starPoint: String)
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(activityMainBinding.root)
    
            activityMainBinding.run{
    
                editTextMovieTitle.run{
                    // 포커스를 가져온다.
                    requestFocus()
                }
    
                thread {
                    if(currentFocus != null){
                        imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                        imm.showSoftInput(currentFocus,0)
                    }
                }
    
    
                // 시크바에서 현재 가격을 보여준다.
                seekBarMovePrice.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
                    override fun onProgressChanged(
                        seekBar: SeekBar?,
                        progress: Int,
                        fromUser: Boolean
                    ) {
                        // 가격이 변한다면 하기 텍스트 뷰에 현재 가격을 표시한다.
                         textViewPriceText.text = "${progress * 1000}원"
                    }
                    override fun onStartTrackingTouch(seekBar: SeekBar?) {
                    }
                    override fun onStopTrackingTouch(seekBar: SeekBar?) {
                    }
                })
    
                // 관람등급을 선택하면 표시를 한다.
                chipLookAge.run{
                    setOnCheckedChangeListener { group, checkedId ->
                        when(checkedId){
                            chipAgeAll.id -> {
                                textViewSelectLookAge.text = "전체연령가 선택되었습니다."
                                chipAgeAll.setTextColor(Color.BLACK)
                                chipAge12.setTextColor(Color.WHITE)
                                chipAge15.setTextColor(Color.WHITE)
                                chipAgeAdult.setTextColor(Color.WHITE)
                            }
                            chipAge12.id -> {
                                textViewSelectLookAge.text = "12세 연령가 선택되었습니다."
                                chipAgeAll.setTextColor(Color.WHITE)
                                chipAge12.setTextColor(Color.BLACK)
                                chipAge15.setTextColor(Color.WHITE)
                                chipAgeAdult.setTextColor(Color.WHITE)
                            }
                            chipAge15.id -> {
                                textViewSelectLookAge.text = "15세 연령가 선택되었습니다."
                                chipAgeAll.setTextColor(Color.WHITE)
                                chipAge12.setTextColor(Color.WHITE)
                                chipAge15.setTextColor(Color.BLACK)
                                chipAgeAdult.setTextColor(Color.WHITE)
                            }
                            chipAgeAdult.id -> {
                                textViewSelectLookAge.text = "성인 연령 선택되었습니다."
                                chipAgeAll.setTextColor(Color.WHITE)
                                chipAge12.setTextColor(Color.WHITE)
                                chipAge15.setTextColor(Color.WHITE)
                                chipAgeAdult.setTextColor(Color.BLACK)
                            }
                        }
                    }
                }
    
                // 레이팅바에서 현재 평점을 보여준다.
                ratingBar3.run{
                    setOnRatingBarChangeListener { ratingBar, rating, fromUser ->
                        textViewStarPoint.text = rating.toString()
                    }
                }
    
                //data class Move(val moveName: String, val MDName: String, val price: String, val lookAge: String, val starPoint: String)
                // 영화 감독의 이름을 받고 엔터를 눌렀을 경우
                editTextMDName.run{
                    setOnEditorActionListener { v, actionId, event ->
                        val movieName = editTextMovieTitle.text.toString()
                        val mdName = editTextMDName.text.toString()
                        val price = seekBarMovePrice.progress * 1000
                        var lookAge = when(chipLookAge.checkedChipId){
                            chipAgeAll.id -> {
                                "전체"
                            }
                            chipAge12.id -> {
                                "12세"
                            }
                            chipAge15.id -> {
                                "15세"
                            }
                            chipAgeAdult.id -> {
                                "성인"
                            }
                            // 만약 그냥 넘길 경우
                            else ->{
                                "전체"
                            }
    
                        }
    
                        val starPoint = ratingBar3.rating.toString()
    
                        val movie = Movie(movieName, mdName, price, lookAge, starPoint)
                        movieList.add(movie)
    
                        editTextMovieTitle.text.clear()
                        seekBarMovePrice.progress = 5
                        chipLookAge.check(chipAgeAll.id)
                        textViewSelectLookAge.text = "전체연령가 선택되었습니다."
                        ratingBar3.progress = 0
                        editTextMDName.text.clear()
    
                        // 영화 제목에 포커스를 준다.
                        editTextMovieTitle.requestFocus()
                        true
                    }
    
                }
    
                // 버튼 눌렀을때
                buttonLoadData.run{
                    setOnClickListener {
                        textViewPrintData.text = ""
                        for(movie in movieList){
                            textViewPrintData.append("영화제목 : ${movie.movieName}\n")
                            textViewPrintData.append("영화요금 : ${movie.price}\n")
                            textViewPrintData.append("관람등급 : ${movie.lookAge}\n")
                            textViewPrintData.append("별점 : ${movie.starPoint}\n")
                            textViewPrintData.append("영화감독 : ${movie.mdName}\n")
                            textViewPrintData.append("\n")
                        }
    
                    }
                }
    
            }
        }
    
    
    }

    실행 화면 입니다.

    시작 화면
    영화 제목을 입력 후 엔터키를 눌렀을 때
    감독 이름 입력 후 모습

    해당 크기 때문인지 바로 감독이름으로 넘어가는 것은 해결하지 못하여, 기본 값이 들어 갈 수 있도록 지정해 놓았습니다.

    시크바를 이용하여 영화 가격 설정, Chip를 이용하여 연령가 설정 레이팅바를 이용한 별점 설정 하는 화면 입니다.

     

    감독이름을 입력 후 엔터를 눌러 밑으로 스크롤 한 모습입니다.

     

     

     

    마무리

    오늘의 복습내용은 문제를 풀면서 시간이 적어 평소보다 자세하게 적지 못하였습니다.

    하지만 문제 작성하는 날이 적다면 당일 배운 내용을 복습하는 내용과 평소보다 못적은 글들에 대해서 내용 보충을 할 수 있도록 하겠습니다.

     

    오늘의 마음가짐

    남들이 다 안한다고 안하지 말고 굳게 가자

     

Designed by Tistory.