[내배캠 Android 4기] TIL 사전캠프 8일차

오리너구리·2024년 5월 9일
0

TIL

목록 보기
8/48
post-thumbnail

TIL(Today I Learned)

  • Android 개발 종합반 2주차 강의듣기

오늘 만든 화면 Layout

레이아웃

실행 영상

레이아웃에 사용한 요소

  1. ImageView
  2. TextView
  3. NumberPicker
  4. Button
  5. LinearLayout

구현할 기능

  1. NumberPicker 의 값을 로또 추첨에 사용되는 범위(1~45)로 지정하기

  2. 뽑힌 번호 숫자에 맞춰 실제 로또 공이랑 같은 색의 배경이 나오도록 지정하기

    (1-10 : 노랑 11-20 파랑 21-30 빨강 31-40 회색 41-45 녹색)

  3. 번호 추가하기 버튼눌렀을때

    1. 사용자가 원하는 번호 추가하기
    2. 선택한 번호가 5개 이상이면 > “숫자는 최대 5개까지 선택 할 수있습니다” 메세지 띄우기
    3. 이미 6개 번호가 다 차 있으면 > “초기화 후에 시도해주세요” 메세지 띄우기
    4. 중복된 번호를 선택하면 > “이미 선택된 숫자 입니다” 메세지 띄우기
  4. 자동 생성하기 버튼 눌렀을 때 사용자가 선택한 숫자를 제외한 숫자 들 중 랜덤한 숫자를 골라주기

  5. 초기화 버튼 눌렀을 때 초기화 되게 만들기

.

  1. 뷰바인딩 형식으로 레이아웃과 코드를 연결해준다.

    1. build.gradle.kts(Module :app) 에서 buildFeatures **{** viewBinding = true 추가

    2. MainActivity.kt 에

      binding = ActivityMainBinding.inflate(*layoutInflater*)

      setContentView(binding.*root*)

  2. 레이아웃에서 사용할 Button , NumberPicker 등을 가져온다.

    private val clearButton by lazy {binding.btnClear}
        private val addButton by lazy {binding.btnAdd}
        private val runButton by lazy {binding.btnRun}
        private val numPick by lazy {binding.npNum}
    
        private val numTextViewList : List<TextView> by lazy {
            listOf<TextView>(
                binding.tvNum1,
                binding.tvNum2,
                binding.tvNum3,
                binding.tvNum4,
                binding.tvNum5,
                binding.tvNum6
            )
  1. 프로그램이 실행 중인지 확인할 didRun 과 로또 번호가 몇 개 선택 됐는지 확인할 pickNumberSet 변수를 만든다

    	  private var didRun = false
        private val pickNumberSet = hashSetOf<Int>()
  2. 로또 번호의 범위를 지정한다

    	  numPick.minValue = 1
        numPick.maxValue = 45
  3. 3개의 버튼들에 대한 함수를 호출해준다.

    	      initAddButton() // 번호 추가하기 버튼
            initRunButton() // 자동 생성 시작 버튼
            initClearButton() // 초기화 버튼
  4. 번호 추가 하기 버튼을 누르면 조건에 따라 토스트 메세지를 띄우거나 번호를 추가하도록 함수를 만들어준다.

     private fun initAddButton() {
            addButton.setOnClickListener{ 
                when {
                    didRun -> showToast("초기화 후에 시도해주세요")
                    pickNumberSet.size >= 5 -> showToast("숫자는 최대 5개까지 선택 할 수 있습니다.")
                    pickNumberSet.contains(numPick.value) -> showToast("이미 선택된 숫자 입니다.")
                    else -> {
                        val textView = numTextViewList[pickNumberSet.size]
                        textView.isVisible = true
                        textView.text = numPick.value.toString()
                        setNumBack(numPick.value, textView)
                        pickNumberSet.add(numPick.value)
                    }
                }
            }
        }
        private fun showToast(message: String) {
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
        }
  5. 초기화 버튼을 누르면 선택된 번호를 삭제하고,처음상태로 돌아가게 만들어준다.

        private fun initClearButton() {
            clearButton.setOnClickListener {
                pickNumberSet.clear()
                numTextViewList.forEach { it.isVisible = false }
                didRun = false
                numPick.value = 1
            }
        }
  6. 자동 생성 하기 버튼을 누르면 번호를 자동으로 생성하도록 만들어준다.

        private fun initRunButton() {
            runButton.setOnClickListener {
                val list = getRandom()
    
                didRun = true
    
                list.forEachIndexed{index, number ->
                    val textView = numTextViewList[index]
                    textView.text = number.toString()
                    textView.isVisible = true
                    setNumBack(number, textView)
                }
            }
        }
        private fun getRandom(): List<Int> {
            val numbers = (1 .. 45).filter { it !in pickNumberSet }
            return (pickNumberSet + numbers.shuffled().take(6-pickNumberSet.size)).sorted()
        }
    
        private fun setNumBack(number: Int, textView: TextView) {
            val background = when(number) {
                in 1..10 -> R.drawable.circle_yellow
                in 11..20 -> R.drawable.circle_blue
                in 21..30 -> R.drawable.circle_red
                in 31..40 -> R.drawable.circle_gray
                else -> R.drawable.circle_green
            }
                textView.background = ContextCompat.getDrawable(this, background)
            }

새로 알게 된 것들

  1. xml파일을 직접 만들어서 원하는 도형을 만드는 방법

    1. drawable 폴더에 xml 파일을 새로 만든다.

    2. xml 선언부를 적어준다.

      <?xml version="1.0" encoding="utf-8" ?>
    3. xmlns를 통해 기본적인 namespace를 설정하고 rectangle, oval, line ring 중 원하는 모양을 선택한다.

      <shape
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:shape="oval">
    4. 속성을 결정해준다

      • size : 도형 크기
            <size
                android:width="44dp" // 넓이
                android:height="44dp"/> // 높이        
      • solid : 면의 색상
           <solid
                android:color="#1E71FF"/>
      • stroke: 테두리 선
          <stroke
                android:color="@color/black" // 테두리 색상
                android:width="1dp" // 테두리 선 두께
                android:dashGap="5dp" // 점선의 간격
                android:dashWidth="1dp"  // 점선 길이 
                />      
      • corners : 코너 둥글기
        <corners
            android:radius="12dp" //모든 모서리 한번에 적용
            android:bottomLeftRadius="15dp" 
            android:bottomRightRadius="15dp"
            android:topLeftRadius="15dp"
            android:topRightRadius="15dp" />
      • gradients : 그라이언트
        <gradient
            android:type="sweep" // 그라데이션 종류
            android:centerX="0.4" // 중심의 x 값
            android:centerY="0.6" // 중심의 y 값
            android:centerColor="#ffffff" // 가운데 색상
            android:startColor="#ff0000" // start로 설정된 부분의 색
            android:endColor="#0000ff" // end로 설정된 부분의 색
            android:angle="0" //각도
        />
      • padding: 패딩 값
        <padding
            android:bottom="10dp"
            android:left="10dp"
            android:right="10dp"
            android:top="10dp" />
  2. by lazy

    Lazy Initialization (늦은 초기화) 를 하는 방식 중하나

    
    **늦은 초기화** :
    컴퓨터 프로그래밍에서 객체 생성, 값 계산 등 비용이 많이 드는 과정을 처음 필요한 시점까지 지연시키는 기법
    
    클래스 안에 '이 변수를 언젠가 쓸거야' 선언만 해놓고, 나중에 실제로 그 값을 사용 하는 시점에 값을 입력하여 사용하는 것
    
    *lateinit* 과 *by lazy* 의 방법이 있다.
  3. hashSetOf

    hashSetOf를 알기 위해서는 일단 Collection을 알아야 함

    
    **Collection :**
    다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화 된 방법을 제공하는 클래스의 집합
    
    	Collection의 Property
    	﹒size : 컬렉션에 포함된 원소의 개수
    	
    	Collection의 Method
    	﹒contains : 해당 요소가 있는지 없는지 체크하는 함수
    	﹒any : Collection 에 적어도 1개의 요소가 있으면 true를 리턴하는 함수
    	﹒none : Collection에 1개도 match 되는 요소가 없을때 true를 리턴하는 함수
    	﹒all : Collection의 모든 요소가 match 될 때 true를 리턴하는 함수
    	﹒clear : Collection의 모든 기록을 삭제하는 함수

    Kotlin은 자체적으로 기본 컬렉션 타입인 List, Set, Map을 제공한다.

    이 중 List와 Set은 컬렉션을 상속 받고, Map은 독자적이다.

    
    **Set :**
    정의된 순서가 없는 요소 그룹을 나타내는 컬렉션 중복을 허용하지 않는다.
    >>중복을 자동으로 제거해줌.
    	
    	Set의 Method
    	﹒add : Set에 데이터를 추가하는 함수
    	﹒add All : Set에 Collection에 포함된 데이터를 추가하는 함수
    	﹒remove : Set에 데이터를 삭제하는 함수

    주로 순서를 유지하고 중복을 허용 해야 할 때에는 List를 사용하고, 요소가 고유하고 요소의 순서가 중요하지 않을 때에는 Set을 사용한다.

    hashSetOf 는 새로운 인스턴스를 만드는데 사용되는 함수로

    오늘 사용한 코드

      private val pickNumberSet = hashSetOf<Int>()

    에서는 pickNumberSet 이라는 변수에 Int(정수) 세트를 할당하고, 빈 세트로 시작하겠다는 뜻이다.

  4. forEach

    
    **forEach :**
    배열을 순회해서 처리하는데 사용하는 함수.
    배열의 각 요소에 대해 주어진 함수를 순서대로 한 번씩 실행함.
    	
    forEachIndexed :
    forEach와 동일한 기능을 수행하며 value 뿐 아니라 해당 value의 index까지 같이 사용할 수있다.

    오늘 사용한 코드에서는

     numTextViewList.forEach { it.isVisible = false }

    numTextViewList 에 있는 요소들의 isVisible을 하나하나 false로 바꿔주기위해 사용함.

  5. lambda expression (람다식)

    
    **lambda expression :**
    method를 하나의 식으로 표현한 것.
    익명 함수를 지칭하는 용어
    
    람다 표현식:
    1. 람다는 매개변수 화살표(->) 함수몸체로 이용하여 사용 할 수 있다.
    2. 함수몸체가 단일 실행문이면 괄호{}를 생략 할 수 있다. 
    3. 함수몸체가 return문으로만 구성되어 있는 경우 괄호{}를 생략 할 수 없다.
    	
    장점 : 
    불필요한 반복문의 삭제로 복잡한 식을 단순하게 표현 가능하다.
    지연연산을 수행함으로써 불필요한 연산을 최소화 할 수 있다.
    
    단점 :
    람다식의 호출이 까다롭다.
    불필요하게 사용하면 오히려 가독성을 떨어뜨린다.

    오늘 사용한 코드에서는 이렇게 사용됐다. (빨간 형광펜 친 부분)

    list.forEachIndexed { index, number ->
        val textView = numTextViewList[index]
        textView.text = number.toString()
        textView.isVisible = true
        setNumBack(number, textView)
    }
    
      private fun getRandom(): List<Int> {
            val numbers = (1 .. 45).filter { it !in pickNumberSet }
            return (pickNumberSet + numbers.shuffled().take(6-pickNumberSet.size)).sorted()
        }
  6. ContextCompat

    
    **ContextCompat :**
    여러 버전의 Android 플랫폼에서 일관된 방식으로 작동하도록 도와주는 유틸리티 클래스.
    리소스관리, 권한 요청, 레이아웃 인플레이션 등과 같은 작업을 보다 쉽게 수행할 수 있도록 도와주는 여러가지 유틸리티 메서드가 포함되어 있다.
    
    ContextCompat.getDrawable(context, resId) :
    메서드는 주어진 컨텍스트와 리소스 ID에 해당하는 Drawable을 반환합니다. 이를 통해 호환성을 유지하면서 리소스에 액세스할 수 있습니다.

    오늘 사용한 코드에서는 이렇게 사용했다.

    textView.background = ContextCompat.getDrawable(this, background)

    주어진 background 리소스ID에 해당하는 Drawable을 가져와서 textView의 배경으로 설정하라는 뜻.

profile
오리너구리입니다

0개의 댓글