ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TECHIT 앱 스쿨 2기: Android 30일차 (23.06.09)
    [THEC!T] 앱 스쿨2기 : Android 2023. 6. 10. 01:33
    728x90

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

     

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

    강사님께서 작성해주신 코드는 제가 작성한 코드와 비교하자면 가장 큰 부분은 해당 에디트 텍스트에서 엔터키를 누른 경우에 대하여 코드 작성 여부였습니다. 굳이 작성하지 않더라도 엔터키를 누르면 다음 에디트 텍스트로 넘어 가는 것을 알게 되었고 이 외에는 제가 작성한 코드와 큰 차이는 없었습니다.

     

    다음으로는 스크롤 뷰(ScrollView) 에 대해서 학습 및 실습을 하였습니다.

     

    ScrollView

    스크롤 뷰는 배치되어 있는 View가 화면을 벗어 날 경우 스크롤을 할 수 있도록 제공되는 View이며, ScrollView는 위 아래로 스크롤이 가능하고 HorizontalScrollView는 좌 우로 스크롤이 가능합니다. 즉 ScrollView 와 HorizontalScrollView을 조합한다면 상하 좌우 스크롤이 가능합니다.

     

    주요 메서드

    getScrollY : ScrollView에서 현재 스크롤 된 Y 좌표를 가져온다.
    getScrollX : HorizontalScrollView에서 현재 스크롤 된 X 좌표를 가져온다.
    scrollTo : 지정된 위치로 스크롤 한다. ScrollView에서는 Y 좌표를, HorizontalScrollView에서는 X 좌표를 설정한다.
    scrollBy : 현재 위치에서 지정된 값 만큼 이동한다.
    smoothScrollTo : 지정된 위치로 스크롤 한다. 애니메이션이 동작한다.
    smoothScrollBy : 현재 위치에서 지정된 값 만큼 이동한다. 애니메이션이 동작한다.

     

    주요 이벤트

    setOnScrollChangeListener : 스크롤이 변경 되었을 때

    scroll1.run{
        // ScrollView의 Scroll 이벤트
        // 이벤트가 발생한 뷰, 스크롤된 X 좌표, 스크롤된 Y 좌표, 스크롤 되기전 X 좌표, 스크롤 되기전 Y 좌표
        setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            textView2.text = "Y : $oldScrollY -> $scrollY"
        }
    }

     

    다음으로는 TextInputLayout 에 대해서 학습하였습니다.

     

    TextInputLayout 

     

    EditText를 보완한 View이며, EditText의 속성, 이벤트, 프로퍼티 등을 그대로 가져옴과 동시에 몇 가지 요소가 추가되었습니다

     

    주요속성

    hint : 원래는 입력한 내용이 없으면 보여줄 문자열의 의미를 갖지만 여기에서는 안내 문구 용도로 사용한다. 입력한 내용이 있으면 사라지지 않고 상단으로 이동한다.


    counterEnabled : 입력한 글자의 수가 나타난다.


    counterMaxLength : 지정한 글자수를 넘으면 붉은 색으로 표시해준다.

     

    주요 메서드

    editText : TextInputLayout이 가지고 있는 EditText 객체의 주소 값


    error : 오류로 표시할 메시지를 설정한다.

    activityMainBinding.run{
    
        textInputLayout.run {
    
            editText?.run {
                addTextChangedListener {
                    if(it!!.length > 10){
                        textInputLayout.error = "10 글자 이하로 입력해주세요"
                    } else {
                        textInputLayout.error = null
                    }
                }
            }
        }

     

     

    다음으로는 이미지 뷰에 대해서 배웠습니다.

     

    이미지 뷰에 대해서 설명해주시면서 Drawable, mipmap 차이점에 대해서 설명해주셨습니다.

    각각 비트맵 과 벡터방식으로 이미지 처리를 하며 해당 차이점에 대해서도 설명해주셨습니다.

    강사님께서 자세하게 설명해주셨지만 제가 작성하기에는 아직 좀 어려워 챗 gpt의 도움을 좀 받았습니다.

     

    mipmap:
    mipmap 폴더는 앱의 아이콘과 같은 런처 아이콘과 앱 아이콘 같은 이미지들을 저장하는 데 사용됩니다. 안드로이드는 여러 가지 해상도와 크기의 디바이스를 지원하기 때문에, mipmap 폴더에는 각각 다른 해상도의 이미지가 들어 있습니다. 이는 디바이스가 각각에 맞는 이미지를 선택하고 화면에 표시할 수 있도록 도와줍니다. 런처 아이콘은 앱을 사용자의 홈 화면에 표시할 때 사용되며, 안드로이드 스튜디오에서 자동으로 생성될 수 있습니다.

    drawable:
    drawable 폴더는 앱에서 사용되는 그래픽 리소스를 저장하는 데 사용됩니다. 이 폴더는 여러 가지 종류의 이미지 리소스를 포함할 수 있으며, 각각 다른 목적과 사용 방법이 있습니다. drawable 폴더는 다양한 화면 밀도(density)를 가진 디바이스를 지원하기 위해 사용됩니다. 따라서 각각의 drawable 폴더에는 해상도 및 크기에 따라 다른 이미지가 들어 있을 수 있습니다. 예를 들어, drawable-hdpi 폴더에는 고밀도 디바이스에 맞는 이미지가 들어 있고, drawable-mdpi 폴더에는 중간 밀도 디바이스에 맞는 이미지가 들어 있을 수 있습니다. 이렇게 함으로써 안드로이드는 디바이스의 화면 밀도에 맞는 이미지를 선택하여 사용자에게 최적화된 그래픽을 제공할 수 있습니다.

    drawable 폴더는 또한 다른 종류의 리소스, 예를 들어 XML 파일(벡터 드로어블 등)이나 애니메이션 파일도 포함할 수 있습니다. 이들은 앱의 UI 요소의 배경이나 버튼의 모양 등을 정의하는 데 사용될 수 있습니다.

     

    요약하자면, mipmap 폴더는 앱의 아이콘과 같은 런처 아이콘과 앱 아이콘 등을 저장하는 데 사용되며, drawable 폴더는 앱에서 사용되는 다양한 그래픽 리소스를 저장하는 데 사용됩니다. drawable 폴더는 다양한 화면 밀도를 지원하기 위해 사용되며, 각각의 폴더는 해당 디바이스에 맞는 이미지를 선택하여 사용자에게 최적의 그래픽을 제공합니다.

     

    주요 메서드

    srcCompat : 보여줄 이미지를 지정한다.

     

    다음으로는 체크박스와  라디오 버튼에 대해서 학습하였습니다.

     

    체크박스

    선택할 수 있는 항목 들을 제공하고 체크를 통해 선택할 수 있도록 하는 View

    다수의 CheckBox를 동시에 선택 할 수 있다.

     

    주요 메서드

    isChecked : 해당 체크박스에 체크상태를 확인하거나 설정이 가능하다.

    toggle : 현재 체크박스의 상태를 반전 시킨다.

     

    setOnCheckedChangeListener : 체크 박스의 선택 상태가 변경되었을 때 동작

    checkBox.run{
        // 체크 박스의 선택 상태가 변경되었을 때 동작한다.
        // isChecked 안에 선택 상태에 대한 값이 전달된다.
        setOnCheckedChangeListener { buttonView, isChecked ->
            if(isChecked == true){
                textView.text = "첫 번째 체크박스가 체크 되었습니다."
            } else {
                textView.text = "첫 번째 체크박스가 체크 해제 되었습니다."
            }
        }
    }

     

    라디오 그룹

    하나의 그룹 안에서 하나만 선택 할 수 있도록 하는 View 이며, 라디오 그룹 안에는 여러개의 라디오 버튼을 배치 할 수 있으며, 하나만 선택이 가능하다.

     

    주요 속성

    text : RadioButton에 표시되는 문자열을 설정한다.
    checked : 체크 상태를 설정한다. RadioButton은 그룹 내에서 반드시 하나는 선택되어 있는 상태로 제공되는 목적으로 사용하는 View 이므로 반드시 하나는 체크해야 한다.

     

    주요 메서드

    checkedRadioButtonId : 선택되어 있는 라디오 버튼의 id를 가져온다.

     

    setOnCheckedChangeListener : 라디오 그룹 내의 라디오 버튼 선택이 변경 될 경우 호출된다.

    radioGroup1.run{
        // 라디오 그룹 내의 라디오 버튼 선택이 변경될 경우..
        // checkedId : 선택된 라디오 버튼의 ID가 전달된다.
        setOnCheckedChangeListener { group, checkedId ->
            when(checkedId){
                R.id.radioButton ->{
                    textView.text = "라디오 1-1 선택"
                }
                R.id.radioButton2 ->{
                    textView.text = "라디오 1-2 선택"
                }
                R.id.radioButton3 ->{
                    textView.text = "라디오 1-3 선택"
                }
            }
        }
    }

     

     

    다음으로는 어제 배운 내용과 오늘 배운 내용을 바탕으로 작성할 수 있는 문제를 내주셨습니다.

    처음에는 하기와 같은 조건이였으나, 입력화면에 구성할 것이 좀 하단 내용을 확인하기 어려운 문제 등등이 있어

    모두 스크롤 뷰 내에 작성하는 조건으로 변경 되었습니다.

     

    하기는 제가 작성한 애플리케이션 작동 화면과 작성한 코드 입니다.

    시작 화면
    이름 입력 후 엔터키를 누른 경우
    나이 입력 후 엔터키를 눌렀을 경우
    자료 입력 및 선택 후 국어점수 입력 후 엔터 누르기 전
    자료 입력 및 선택 후 국어점수 입력 후 엔터 누른 후

     

    해당 단계를 총 3번 거친 후 학생 정보 출력 버튼을 터치

    스크롤하여 내리기 전 모습
    스크롤 하여 화면을 내린 모습

    작성 코드

    package com.test.android18_study
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.os.SystemClock
    import android.text.method.TextKeyListener.clear
    import android.view.inputmethod.InputMethodManager
    import com.test.android18_study.databinding.ActivityMainBinding
    import kotlin.concurrent.thread
    
    data class Student(val name: String, val age: Int, val menWomen: String, val hobby: String, val korScore: Int)
    var stdList = ArrayList<Student>()
    
    class MainActivity : AppCompatActivity() {
    
        lateinit var activityMainBinding: ActivityMainBinding
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(activityMainBinding.root)
    
            activityMainBinding.run{
    
                thread {
                    SystemClock.sleep(500)
                    val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.showSoftInput(currentFocus, 0)
                }
    
                nameText.run{
                    // 포커스 가져오기
                    requestFocus()
                }
                ageLayoutText.run{
                    setOnEditorActionListener { v, actionId, event ->
                        val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
                        if(currentFocus != null){
                            imm.hideSoftInputFromWindow(windowToken,0)
                            currentFocus!!.clearFocus()
                        }
                        false
                    }
                }
                korScore.run{
    
                    setOnEditorActionListener { v, actionId, event ->
    
                        val name = nameText.text.toString()
                        val age = ageLayoutText.text.toString().toInt()
                        val menWomen = when(selectMenWomen.checkedRadioButtonId){
                            R.id.men -> "남자"
                            R.id.women -> "여자"
                            else -> "오류"
                        }
    
    
                        var hobby = StringBuilder()
                        if(hobby1.isChecked) hobby.append("게임")
                        if(hobby2.isChecked) hobby.append("축구")
                        if(hobby3.isChecked) hobby.append("영상시청")
                        if(hobby.isEmpty()) hobby.append("없음")
    
                        val std = Student(name, age, menWomen, hobby.toString(), korScore.text.toString().toInt())
                        stdList.add(std)
    
                        nameText.setText("")
                        ageLayoutText.setText("")
                        selectMenWomen.clearCheck()
                        hobby1.isChecked = false
                        hobby2.isChecked = false
                        hobby3.isChecked = false
                        korScore.text.clear()
    
                        nameText.requestFocus()
    
                        false
    
                    }
    
                }
    
                printBtn.run{
                    setOnClickListener {
                        var korTotal = 0
                        stdPrintTextView.text = ""
                        for(std in stdList){
                            stdPrintTextView.append("\n")
                            stdPrintTextView.append("이름 : ${std.name}\n")
                            stdPrintTextView.append("나이 : ${std.age}\n")
                            stdPrintTextView.append("성별 : ${std.menWomen}\n")
                            stdPrintTextView.append("취미 : ${std.hobby}\n")
                            stdPrintTextView.append("국어점수 : ${std.korScore}\n")
                            korTotal += std.korScore
                        }
                        stdPrintTextView.append("\n")
                        stdPrintTextView.append("국어점수 총점 : ${korTotal}\n")
                        stdPrintTextView.append("국어점수 평균 : ${korTotal/stdList.size}\n")
                    }
                }
    
            }
    
        }
    
    }

     

    마무리

     

    정말 완벽하게 만드려면 값을 안넣거나, 체크를 안하는 경우도 구현을 해야하는데 아직 정확하게 몰라 생각이 나는 취미에 대해서만 일부 처리를 하였습니다. 처음에는 금방 작성하였었는데 국어점수를 가지고 오는 것을 TextInputLayout 으로 하려다 아직 공부가 부족하였었는지 어플리케이션이 강제종료 되는 문제가 발생하여 editText 를 이용하여 작성하였습니다.

    주말 간 배운내용을 복습하면서 해당 코드 또한 수정을 해볼 수 있도록 하겠습니다.

     

    오늘의 마음가짐

    에러는 개발자를 성장시킨다라는 마인드로 에러를 고쳐나가자

     

Designed by Tistory.