본문 바로가기
안드로이드

로또번호 추첨 어플 만들기

by 디토20 2022. 3. 22.
반응형

이번 강의는 로또번호 추첨 앱 만들기~!

 

 

패스트캠퍼스 불편한점..

댓글기능이나 질문 기능이 없는거같다.

 

인프런같은 경우는

강의들으면서 궁금한건 바로바로 질문도 가능하고

남들이 한 질문을 통해 내 궁금증도 해결할 수 있어서

쌍방 소통이 되는 느낌인데

 

패스트캠퍼스는 그냥 티비보는 느낌?

소통이 전혀 안돼서 답답하다.

 

강의는 확실히 인프런이 낫다

 

 


 

이번에는 화면 전환이 없어 메인액티비티 한개와 drawable, layout, values로 구성이 되어있다.

 

 

 

 

 

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <NumberPicker
        android:id="@+id/numberPicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/addButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="16dp"
        android:text="@string/add_button"
        app:layout_constraintEnd_toStartOf="@+id/clearButton"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/numberPicker" />

    <Button
        android:id="@+id/clearButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/init_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/addButton"
        app:layout_constraintTop_toBottomOf="@+id/numberPicker"
        app:layout_constraintTop_toTopOf="@+id/addButton" />


    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addButton">

        <TextView
            android:id="@+id/textView1"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView2"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView3"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView4"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView5"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView6"
            android:textSize="18sp"
            android:textStyle="bold"
            android:text="1"
            android:background="@drawable/circle_blue"
            android:gravity="center"
            android:textColor="@color/white"
            android:visibility="gone"
            tools:visibility="visible"
            android:layout_margin="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>


    </LinearLayout>

    <Button
        android:id="@+id/runButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:text="@string/start_button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

이번 강의에서는 지난 강의에서 사용된 LinearLayout이 아닌 constraintLayout을 사용했다.

내가 정한 방향대로 차곡차곡 쌓이는 LinearLayout과는 다르게

constraintLayout은 컴포넌트의 위치를 관계를 통해 지정해주어야 한다.

 

 

 

app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

위와 같이 내 컴포넌트의 end 지점을 parent end와 연결하고,

start 지점을 parent start와 연결하고,

 top 지점을 parent top와 연결하겠다는 의미이다.

 

 

 

android:layout_marginEnd="16dp"
android:text="@string/add_button"
app:layout_constraintEnd_toStartOf="@+id/clearButton"
app:layout_constraintHorizontal_chainStyle="packed"

번호 추가 버튼 end 지점과 초기화 버튼 start 지점을 연결해 준 후

번호 추가 버튼의 chainStyle = packed로 지정해주면 두 버튼이 일렬로 딱 붙게되는데

여기서 번호 추가 버튼의 marginEnd를 16dp를 주면

버튼이 적당히 떨어진 것을 볼 수 있다.

 

 

 

 

 

 

그리고 constraintlayout 안에 LinearLayout을 이용해

번호 6개를 일렬로 줄세웠는데, 신기한 점이 있었다.

 

나는 웹개발을 해오다보니까 웹개발에서는 for문을 돌려서 리스트를 출력하면 됐는데

여기는 리스템에 아이템이 6개가 있으면

6개의 컴포넌트를 하나 하나 직접 만들어주었다.

 

android:background="@drawable/circle_blue"
android:gravity="center"
android:textColor="@color/white"
android:visibility="gone"
tools:visibility="visible"

숫자 뒤 동그라미 부분은 background를 이용해 그려주었고,

visibility = gone 을 통해 처음에는 값이 안보이게 숨김 처리를 해 준뒤

나중에 번호가 뽑히면 

MainActivity에서 visible을 활성화 시켜서 보이게 하는 방식으로 개발이 되었다.

 

그러나 개발할때는 안보이면 불편하기 때문에

tools:visibility = visible을 이용해 개발창에는 전부 출력이 되게 만들어주었다!

 

 

NumberPicker라는 기능을 처음 사용해봤다.

이 컴포넌트를 사용하면 내가 정해준 min값 ~ max값 내에서 스크롤을 이용해 버튼을 선택할 수 있다.

 

 

 

 

 

MainActivity.kt
package fastcampus.aop_part2_chapter02

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.NumberPicker
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible

class MainActivity : AppCompatActivity() {

    private val clearButton : Button by lazy {
        findViewById<Button>(R.id.clearButton)
    }

    private val addButton : Button by lazy {
        findViewById<Button>(R.id.addButton)
    }
    private val runButton : Button by lazy {
        findViewById<Button>(R.id.runButton)
    }

    private val numberPicker : NumberPicker by lazy {
        findViewById<NumberPicker>(R.id.numberPicker)
    }

    private val numberTextViewList : List<TextView> by lazy {
        listOf<TextView>(
            findViewById<TextView>(R.id.textView1),
            findViewById<TextView>(R.id.textView2),
            findViewById<TextView>(R.id.textView3),
            findViewById<TextView>(R.id.textView4),
            findViewById<TextView>(R.id.textView5),
            findViewById<TextView>(R.id.textView6)
        )
    }

    private var didRun = false

    private val pickNumberSet = hashSetOf<Int>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        numberPicker.maxValue = 45
        numberPicker.minValue = 1

        initRunButton()
        initAddButton()
        initClearButton()
    }

    private fun initRunButton() {
        runButton.setOnClickListener {
            val list = getRandomNumber()

            didRun = true

            list.forEachIndexed{ index, number ->
                val textView = numberTextViewList[index]
                textView.text = number.toString()
                textView.isVisible = true
                setNumberBackground(number, textView)

            }

            Log.d("MainActivity", list.toString())
        }
    }

    private fun initAddButton() {
           addButton.setOnClickListener {
               if(didRun){
                   Toast.makeText(this, "초기화 후에 시도해주세요.", Toast.LENGTH_SHORT).show()
                   return@setOnClickListener
               }
               if( pickNumberSet.size >= 5) {
                   Toast.makeText(this, "번호는 5개까지만 선택할 수 있습니다.", Toast.LENGTH_SHORT).show()
                   return@setOnClickListener
               }

               if( pickNumberSet.contains(numberPicker.value)) {
                   Toast.makeText(this, "이미 선택된 번호입니다.", Toast.LENGTH_SHORT).show()
                   return@setOnClickListener
               }

                val textView = numberTextViewList[pickNumberSet.size]
               textView.isVisible = true
               textView.text = numberPicker.value.toString()

                setNumberBackground(numberPicker.value, textView)

               pickNumberSet.add(numberPicker.value)

           }
    }

    private fun setNumberBackground(number : Int, textView : TextView){
        textView.background = when(number) {
            in 1..10 -> ContextCompat.getDrawable(this, R.drawable.circle_yellow)
            in 11..20 -> ContextCompat.getDrawable(this, R.drawable.circle_blue)
            in 21..30 -> ContextCompat.getDrawable(this, R.drawable.circle_red)
            in 31..40 -> ContextCompat.getDrawable(this, R.drawable.circle_gray)
            else -> ContextCompat.getDrawable(this, R.drawable.circle_green)
        }
    }

    private fun initClearButton() {
        clearButton.setOnClickListener {
            pickNumberSet.clear()
            numberTextViewList.forEach{
                it.isVisible = false
            }

            didRun = false
        }
    }

    private fun getRandomNumber(): List<Int> {
        val numberList = mutableListOf<Int>()
            .apply {
                for (i in 1..45) {
                    if(pickNumberSet.contains(i)){
                        continue
                    }
                    this.add(i)
                }
            }

        numberList.shuffle()

        return (pickNumberSet.toList() + numberList.subList(0, 6 - pickNumberSet.size)).sorted()
    }
}

by lazy로 버튼을 지연 초기화 시켜주었다.

by lazy는 변수가 사용될 때 초기화 하라는 뜻!

 

해당 페이지가 onCreate 될때 numberPicker의 max와 min값을 초기화 시켜주고,

버튼 세개를 활성화 시켜주는 함수를 넣어주었다.

 

 

private fun initAddButton() {
       addButton.setOnClickListener {
           if(didRun){
               Toast.makeText(this, "초기화 후에 시도해주세요.", Toast.LENGTH_SHORT).show()
               return@setOnClickListener
           }
           if( pickNumberSet.size >= 5) {
               Toast.makeText(this, "번호는 5개까지만 선택할 수 있습니다.", Toast.LENGTH_SHORT).show()
               return@setOnClickListener
           }

           if( pickNumberSet.contains(numberPicker.value)) {
               Toast.makeText(this, "이미 선택된 번호입니다.", Toast.LENGTH_SHORT).show()
               return@setOnClickListener
           }

            val textView = numberTextViewList[pickNumberSet.size]
           textView.isVisible = true
           textView.text = numberPicker.value.toString()

            setNumberBackground(numberPicker.value, textView)

           pickNumberSet.add(numberPicker.value)

       }
}

우선 번호를 추가하는 함수에는 예외처리들을 해주었는데

이미 자동 생성 시작을 눌렀거나, 수동으로 추가한 번호가 5개 이상이거나, 같은 번호를 이미 선택했을 경우는

Toast 메세지를 출력 하고 OnClickListener를 빠져나오게 해주었고

 

정상적으로 처리가 잘 되었을땐

isVisible = true를 이용해 해당번호가 보이게 변경해주고

번호에 따른 background 색을 저장해 준 뒤

선택된 번호를 Set Collection에 넣어주었다.

 

 

 

circle_blue.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <solid android:color="#5FB5DB"/>

    <size
        android:width="44dp"
        android:height="44dp"/>
</shape>

이 부분은 번호를 감싸는 동그라미를 그리는 xml이다

6개 파일이 전부 같고 color만 다르게 지정해주었다.

 

 

 

 

strings.xml
<resources>
    <string name="app_name">aop-part2-chapter02</string>
    <string name="add_button">번호 추가하기</string>
    <string name="init_button">초기화</string>
    <string name="start_button">자동 생성 시작</string>
</resources>

strings.xml도 간단하게 만들어주었다.

 

 

 

 

 

 

 

 

2, 43, 35를 추가한 후 자동 생성을 하면

2, 43, 35를 포함한 숫자 6개가 정렬되어 출력된다.

 

초기화를 누르고 자동 생성 시작을 누르면

랜덤 6개가 정렬되어 출력되었다.

 

오늘의 실습 끝~

728x90
반응형

댓글