본문 바로가기

Android Project

[Android/Kotlin] 퀴즈앱(1)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:background="@drawable/ic_bg"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Quiz app!"
        android:textSize="25sp"
        android:textStyle="bold"
        android:layout_marginBottom="30dp"
        android:gravity="center"
        android:textColor="@color/white" />


    
    <com.google.android.material.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        app:cardCornerRadius="10dp"
        android:background="@color/white">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Welcome"
                android:textSize="30sp"
                android:textStyle="bold"
                android:gravity="center"
                android:textColor="#362A43" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="이름을 입력하세요"
                android:layout_marginTop="16dp"
                android:textSize="16sp"
                android:textStyle="bold"
                android:gravity="center"
                android:textColor="#7A8089" />

            
            <com.google.android.material.textfield.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                android:layout_marginTop="20dp">

                <androidx.appcompat.widget.AppCompatEditText
                    android:id="@+id/et_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Name"
                    android:inputType="textCapWords"
                    android:textColor="#362A43"
                    android:textColorHint="#7A8089"/>
                
            </com.google.android.material.textfield.TextInputLayout>

            
            <Button
                android:id="@+id/btn_start"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:background="@color/design_default_color_primary"
                android:text="Start"
                android:textColor="@color/white"
                android:textSize="18sp"/>


        </LinearLayout>



    </com.google.android.material.card.MaterialCardView>


</LinearLayout>

activity_main.xml

 

activity_main.xml

 

xml로 메인화면 이미지를 만들고

 

 

 

package com.example.quizapp

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast

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

        // 변수 초기화
        val btnStart : Button = findViewById(R.id.btn_start)
        val etName : EditText = findViewById(R.id.et_name)


        //btn_start버튼 눌렀을때
        btnStart.setOnClickListener {

            //텍스트가 비어있는지 아닌지 확인
            //텍스트가 비어있다면 토스트메세지를 출력
            if(etName.text.isEmpty()){
                Toast.makeText(this,"이름을 입력해주세요", Toast.LENGTH_SHORT).show()
            }else{
                //텍스트가 비어있지 않다면 QuizQuestionActivity로 이동
                val intent = Intent(this, QuizQuestionActivity::class.java)
                startActivity(intent)
                finish()
            }
        }

    }
}

MainActivity.kt

 

코틀린 코드를 통해서 이름을 안적었다면 "이름을 입력해주세요" 라는 토스트메시지가 뜨고,

이름을 적고 start버튼을 누르면 다음 엑티비티로(QuizQuestionActivity) 넘어가도록했다

 

 

 

package com.example.quizapp


//퀴즈에 들어갈 데이터클래스 생성 (데이터클래스의 속성 정하기)
data class Question(
    val id : Int,               //id
    val question : String,      //질문
    val image : Int,            //이미지 (int타입으로 이미지만들수있음)
    val optionOne : String,     //정답체크옵션1
    val optionTwo : String,     //정답체크옵션2
    val optionThree : String,   //정답체크옵션3
    val optionFour : String,    //정답체크옵션4
    val correctAnswer : Int     //정답
    

)

Question.kt

 

Question.kt이라는 코틀린 파일을 만들고 여기에  QuizQuestionActivity에 들어갈 데이터클래스를 만든다

 

 

package com.example.quizapp


// 실제 들어갈 데이터값 만들기
object Constants {

    //이 함수를 실행시켰을때 Question에 담긴 데이터들을 전부 가져오도록
    fun getQuestions() : ArrayList<Question>{
        //questionsList에 각각의 질문에 해당하는 값이 담겨있음
        val questionsList = ArrayList<Question>()

        // que1
        val que1 = Question(
            1, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_argentina,
            "Argentina", "Australia",
            "Armenia", "Austria",
            1
        )
        questionsList.add(que1)

        //que2
        val que2 = Question(
            2, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_australia,
            "Angola", "Austria",
            "Australia", "Armenia",
            3
        )
        questionsList.add(que2)

        //que3
        val que3 = Question(
            3, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_belgium,
            "Bahamas", "Belgium",
            "Barbados", "Belize",
            2
        )
        questionsList.add(que3)

        //que4
        val que4 = Question(
            4, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_denmark,
            "Dominica", "Egypt",
            "Denmark", "Ethiopia",
            3
        )
        questionsList.add(que4)

        //que5
        val que5 = Question(
            5, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_fiji,
            "Gabon", "France",
            "Fiji", "Finland",
            3
        )
        questionsList.add(que5)


        //que6
        val que6 = Question(
            6, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_germany,
            "Germany", "Georgia",
            "Greece", "none of these",
            1
        )
        questionsList.add(que6)


        //que7
        val que7 = Question(
            7, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_india,
            "Ireland", "Iran",
            "Hungary", "India",
            4
        )
        questionsList.add(que7)


        //que8
        val que8 = Question(
            8, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_kuwait,
            "Kuwait", "Jordan",
            "Sudan", "Palestine",
            1
        )
        questionsList.add(que8)


        //que9
        val que9 = Question(
            9, "이 국기는 어느나라의 국기일까요?",
            R.drawable.ic_flag_of_new_zealand,
            "Australia", "New Zealand",
            "Tuvalu", "United States of America",
            2
        )
        questionsList.add(que9)




        return questionsList
    }


}

Constants.kt

 

Question.kt에서 만들어놨던 데이터클래스를 토대로 실제 들어갈 구체적인 데이터를 적어준다

나는 국기를 보여주고 해당국기가 어느나라 국기인지 고르는 퀴즈를 만들것이기 때문에 거기에 해당하는 데이터를 넣어줬다

 

 

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    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"
    android:fillViewport="true"
    tools:context=".QuizQuestionActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/tv_question"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:gravity="center"
            android:textColor="#363A43"
            android:textSize="22sp"
            tools:text="이 국기는 어느나라의 국기일까요?" />

        <ImageView
            android:id="@+id/iv_image"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:contentDescription="Quiz Image"
            tools:src="@drawable/ic_flag_of_germany"/>
        
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:layout_marginTop="16dp"
            android:orientation="horizontal">

            <ProgressBar
                android:id="@+id/progressBar"
                android:layout_width="0dp"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:max="9"
                android:indeterminate="false"
                android:minHeight="50dp"
                android:progress="5"/>
            
            <TextView
                android:id="@+id/tv_progress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:padding="15dp"
                android:textSize="14sp"
                tools:text="0/9"/>

        </LinearLayout>


        <TextView
            android:id="@+id/tv_option_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/option"
            android:gravity="center"
            android:padding="15dp"
            android:textColor="#7A8089"
            android:textSize="18sp"
            tools:text="Apple"/>

        <TextView
            android:id="@+id/tv_option_two"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/option"
            android:gravity="center"
            android:padding="15dp"
            android:textColor="#7A8089"
            android:textSize="18sp"
            tools:text="Apple"/>

        <TextView
            android:id="@+id/tv_option_three"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/option"
            android:gravity="center"
            android:padding="15dp"
            android:textColor="#7A8089"
            android:textSize="18sp"
            tools:text="Apple"/>

        <TextView
            android:id="@+id/tv_option_four"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@drawable/option"
            android:gravity="center"
            android:padding="15dp"
            android:textColor="#7A8089"
            android:textSize="18sp"
            tools:text="Apple"/>

        <Button
            android:id="@+id/btn_submit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@color/design_default_color_primary"
            android:text="제출하기"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:textStyle="bold"/>

    </LinearLayout>

</ScrollView>

activity_quiz_question.xml

 

이제 이름을 입력하고 start버튼을 누르면 나타날 화면인 xml을 만든다

 

 

android:fillViewport="true"  -> 스크롤뷰 한화면에 레이아웃이 다 보이게하는것

android:indeterminate="false" -> 진행바 고정

 

그리고 정답 옵션(4개의 옵션) 클릭하는 부분은 버튼으로 만든게 아니고 TextView를 사용해서 버튼처럼 만든것이다

 

 

activity_quiz_question.xml

 

 

 

package com.example.quizapp

import android.graphics.Color
import android.graphics.Typeface
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.View.OnClickListener
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.core.content.ContextCompat



class QuizQuestionActivity : AppCompatActivity(), OnClickListener{

    //현재위치를 정함
    private var mCurrentPosition : Int = 1
    //질문의 ArrayList?
    private var mQuestionsList : ArrayList<Question>? = null
    //어떤 옵션을 선택했는지 확인하기위해
    private var mSelectedOptionPosition : Int = 0

    private var tvQuestion : TextView? = null
    private var ivImage : ImageView? = null
    private var progressBar : ProgressBar? = null
    private var tvProgress : TextView? = null

    private var tvOptionOne : TextView? = null
    private var tvOptionTwo : TextView? = null
    private var tvOptionThree: TextView? = null
    private var tvOptionFour : TextView? = null
    private var btnSubmit : Button? = null



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

        tvQuestion = findViewById(R.id.tv_question)
        ivImage = findViewById(R.id.iv_image)
        progressBar = findViewById(R.id.progressBar)
        tvProgress = findViewById(R.id.tv_progress)
        tvOptionOne = findViewById(R.id.tv_option_one)
        tvOptionTwo = findViewById(R.id.tv_option_two)
        tvOptionThree = findViewById(R.id.tv_option_three)
        tvOptionFour = findViewById(R.id.tv_option_four)
        btnSubmit = findViewById(R.id.btn_submit)


        tvOptionOne?.setOnClickListener(this)
        tvOptionTwo?.setOnClickListener(this)
        tvOptionThree?.setOnClickListener(this)
        tvOptionFour?.setOnClickListener(this)
        btnSubmit?.setOnClickListener(this)


        // mQuestionsList 로드
        mQuestionsList = Constants.getQuestions()

        setQuestion()

    }

    private fun setQuestion() {

        // Constants.kt에 적은 데이터값이 나오도록 연결
        // index 1번에 해당하는 질문부터 시작하고싶기때문에 1로 설정
//        mCurrentPosition = 1
        val question: Question = mQuestionsList!![mCurrentPosition - 1]
        //tvQuestion 들어갈값 표시
        tvQuestion?.text = question.question
        //ivImage 들어갈값 표시 (image를 int값으로 지정했기때문에 setImageResource로 표시)
        ivImage?.setImageResource(question.image)
        //progressBar 들어갈값 표시
        progressBar?.progress = mCurrentPosition
        // tvProgress 들어갈값 표시
        tvProgress?.text = "$mCurrentPosition/${progressBar?.max}"
        //tvOption 4개에 들어갈값 표시
        tvOptionOne?.text = question.optionOne
        tvOptionTwo?.text = question.optionTwo
        tvOptionThree?.text = question.optionThree
        tvOptionFour?.text = question.optionFour


        // 마지막화면버튼에는 finish버튼 표시
        // 현재위치랑 mQuestionsList의 사이즈가 같다면 if문 실행
        // 현재위치가 마지막이라면 if문 실행
        if (mCurrentPosition == mQuestionsList!!.size){
            btnSubmit?.text = "FINISH"
        }else{
            btnSubmit?.text = "제출하기"
        }
    }


    // 옵션버튼 누르기전 기본값 (defaultOptionsView변수 생성)
    private fun defaultOptionsView(){
        //옵션버튼의 TextView
        val options = ArrayList<TextView>()
        tvOptionOne?.let {
            options.add(0,it)   //index=0, it=실제 optionOne의 텍스트뷰
        }
        tvOptionTwo?.let {
            options.add(1,it)   //index=1, it=실제 tvOptionTwo의 텍스트뷰
        }
        tvOptionThree?.let {
            options.add(2,it)   //index=1, it=실제 tvOptionThree의 텍스트뷰
        }
        tvOptionFour?.let {
            options.add(3,it)   //index=1, it=실제 tvOptionFour의 텍스트뷰
        }

        // for 반복문으로 option안의 option을 확인
        for(option in options){
            //options(옵션버튼의 TextView)의 색상이 바뀌도록
            option.setTextColor(Color.parseColor("#7A8089"))
            // Typeface를 DEFAULT값으로 설정해서 옵션 선택했을때 바뀌도록
            option.typeface = Typeface.DEFAULT
            //배경
            option.background = ContextCompat.getDrawable(
                this, R.drawable.option
            )
        }
    }


    //옵션을 눌렀을때 보여주는값
    private fun selectedOptionView(tv:TextView, selectedOptionNum : Int){
        //defaultOptionsView를 불러와서 모든버튼을 기본으로 돌아가게함
        defaultOptionsView()

        mSelectedOptionPosition = selectedOptionNum

        //텍스트뷰 색상,볼드체,배경 설정
        tv.setTextColor(Color.parseColor("#363A43"))
        tv.setTypeface(tv.typeface, Typeface.BOLD)
        tv.background = ContextCompat.getDrawable(
            this, R.drawable.selected_option
        )
    }


    override fun onClick(v: View?) {
        //textview를 눌렀을때
        when(v?.id){
            //tv_option_one를 눌렀을때 실행할옵션
            R.id.tv_option_one -> {
                tvOptionOne?.let {
                    selectedOptionView(it,1)
                }
            }
            R.id.tv_option_two -> {
                tvOptionTwo?.let {
                    selectedOptionView(it,2)
                }
            }
            R.id.tv_option_three -> {
                tvOptionThree?.let {
                    selectedOptionView(it,3)
                }
            }
            R.id.tv_option_four -> {
                tvOptionFour?.let {
                    selectedOptionView(it,4)
                }
            }

            // btn_submit을 눌렀을때 실행할옵션
            R.id.btn_submit -> {
                //코드 적어야함
            }
        }
    }
}

QuizQuestionActivity.kt

 

실제 동작화면 코드를 구현한다

아직 제출하기 버튼을 눌렀을때를 구현하지 않았고, 옵션버튼을 눌렀을때 색상이 바뀌는 동작만 구현했다

 

val question: Question = mQuestionsList!![currentPosition - 1] 
이 코드에서 mQuestionsList!!라고 써준것은 mQuestionsList변수가 비면 안되기때문에 써주었다

 

 

 

이렇게 동작이 구현됐다

 

다음시간에 퀴즈앱 마무리를 지어봐야겠다!