Android Study
Android Study(Making App #Quiz)
Box Maker
2023. 4. 7. 00:19
1. Quiz 앱 만들기
- 목표
- 총 8개의 퀴즈를 만들어 화면에 퀴즈가 1번부터 8번까지 하나씩 보이게 합니다.
- True, False 버튼을 만들어 사용자가 퀴즈의 답을 클릭하면 정답인지 아닌지 알려줍니다.
- Prev, Next 버튼을 만들어 1번부터 8번까지 퀴즈를 앞뒤로 이동할수 있게 합니다.
완성화면)
1) TextView와 Button 만들기
- 퀴즈가 들어가는 TextView와 각 Button을 디자인한 xml코드는 다음과 같다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2196F3"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@string/image_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_launcher_foreground" />
<TextView
android:id="@+id/question_text_view"
style="@style/TextStyle"
android:layout_width="0dp"
android:layout_height="29dp"
android:layout_marginTop="40dp"
android:text="@string/placeholder"
android:textColor="#212121"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<Button
android:id="@+id/true_button"
style="@style/ButtonStyle"
android:text="@string/true_button_text"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/false_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<Button
android:id="@+id/false_button"
style="@style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="@string/false_button_text"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/true_button"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<Button
android:id="@+id/next_button"
style="@style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/next_button_text"
android:textColor="#000000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/prev_button"
app:layout_constraintTop_toBottomOf="@+id/true_button" />
<Button
android:id="@+id/prev_button"
style="@style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/prev_button_text"
android:textColor="#000000"
app:layout_constraintEnd_toStartOf="@+id/next_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/false_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TextStyle">
<item name="android:layout_marginStart">8dp</item>
<item name="android:layout_marginEnd">8dp</item>
<item name="android:fontFamily">@font/croissant_one</item>
<item name="android:padding">@dimen/text_padding</item>
<item name="android:textAlignment">textStart</item>
</style>
<style name="ButtonStyle" parent="TextStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:backgroundTint">#D15858</item>
<item name="android:textAlignment">center</item>
</style>
</resources>
string.xml
<resources>
<string name="app_name">True Citizen</string>
<string name="false_button_text">false</string>
<string name="true_button_text">True</string>
<string name="prev_button_text">prev</string>
<string name="next_button_text">next</string>
<string name="placeholder">Question goes here</string>
<string name="image_description">A droid icon image</string>
<string name="question_declaration">The (U.S.) Declaration of Independence was Adopted in 1776.</string>
<string name="correct_answer">That\'s correct</string>
<string name="wrong_answer">That\'s incorrect</string>
<string name="question_constitution">The Supreme law of the land is the Constitution.</string>
<string name="question_amendments">The (U.S.) Constitution has 26 Amendments.</string>
<string name="question_independence_rights">The two rights in the Declaration of Independence are:
\n \t <b>life</b> \n \t <b>pursuit of happiness</b>.</string>
<string name="question_religion">Freedom of religion means:
\n \t <b>You can practice any religion, or not practice a religion</b>.</string>
<string name="question_government">Journalists is one branch or part of the government.</string>
<string name="question_government_feds">Congress does not make federal laws.</string>
<string name="question_government_senators">There are one hundred (100) U.S. Senators.</string>
</resources>
2) 기능 구현하기
목표에서 설명한 순서대로 다음과 같이 기능을 구현해보겠다.
2-1 화면에 퀴즈 출력
Question.java
public class Question {
private int answerResId;
private boolean answerTrue;
public Question(int answerResId, boolean answerTrue) {
this.answerResId = answerResId;
this.answerTrue = answerTrue;
}
public int getAnswerResId() {
return answerResId;
}
public void setAnswerResId(int answerResId) {
this.answerResId = answerResId;
}
public boolean isAnswerTrue() {
return answerTrue;
}
public void setAnswerTrue(boolean answerTrue) {
this.answerTrue = answerTrue;
}
}
- Question 클래스를 새로 생성한다.
- 생성자를 생성하여 각 퀴즈의 id값(answerResId), 퀴즈의 정답(answerTrue)변수들을 초기화한다.
- 다른 클래스에서 변수를 수정할 수 있도록 getter/setter를 생성한다.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private Question[] questionBank = new Question[] {
//create/instantiate/question object
new Question(R.string.question_amendments, false),
new Question(R.string.question_constitution, true),
new Question(R.string.question_declaration, true),
new Question(R.string.question_independence_rights, true),
new Question(R.string.question_religion, true),
new Question(R.string.question_government, false),
new Question(R.string.question_government_feds, false),
new Question(R.string.question_government_senators, true),
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}
- 뷰의 id값을 해당 파일로 가져오기 위해서 findViewById()가 아닌 binding을 사용한다.
- 퀴즈들을 배열로 선언하기 위해서 배열형태의 questionBank를 생성한다.
- string.xml에 있는 문제들의 id이름을 정답과 같이 하나씩 배열의 인스턴스로 생성한다.
- setContentView로 화면을 디자인한 리소스 id를 해당 파일에서 사용할 수 있게 한다.
- 그 밑줄은 binding 방식으로 리소스 id를 해당파일에서 사용할 수 있게 해준다.
2-2 Prev, Next 버튼 기능 구현
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private int currentQuestionIndex = 0;
binding.nextButton.setOnClickListener(view -> {
currentQuestionIndex = (currentQuestionIndex + 1) % questionBank.length;
updateQuestion();
});
binding.prevButton.setOnClickListener(view -> {
if (currentQuestionIndex > 0) {
currentQuestionIndex = (currentQuestionIndex - 1) % questionBank.length;
updateQuestion();
}
});
}
private void updateQuestion() {
binding.questionTextView.setText(questionBank[currentQuestionIndex].getAnswerResId());
}
}
- next버튼 클릭 시 다음퀴즈를 보여주고 prev버튼 클릭 시 이전 퀴즈를 보여준다.
- 먼저 updateQuestion 메소드를 생성한다.
- 해당 메소드는 questionBank 배열을 이용해 퀴즈id값을 가져온다.
- 처음 페이지에서 next 버튼을 클릭하면 (0+1)%8이 되어 나머지값인 1이 currentQuestionIndex 변수에 삽입된다. 따라서 updateQuestion 메소드로 넘어가 questionBank[1]이 되어 2번째 퀴즈를 보여주게 된다.
- 2번째 페이지에서 prev버튼을 클릭하면 (1-1)%8이 되어 나머지값인 0이 currentQuestionIndex 변수에 삽입된다. 따라서 updateQuestion 메소드로 넘어가 questionBank[0]이 되어 1번째 퀴즈를 보여주게 된다.
2-3 True, False 버튼 기능 구현
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.trueButton.setOnClickListener(view -> checkAnswer(true));
binding.falseButton.setOnClickListener(view -> checkAnswer(false));
}
private void checkAnswer(boolean userChoseCorrect) {
boolean answerIsCorrect = questionBank[currentQuestionIndex].isAnswerTrue();
int messageId;
if (answerIsCorrect == userChoseCorrect) {
messageId = R.string.correct_answer;
}else {
messageId = R.string.wrong_answer;
}
Snackbar.make(binding.imageView, messageId, Snackbar.LENGTH_SHORT)
.show();
}
- checkAnswer 메소드를 생성해 boolean 리턴타입을 가진 userChosenCorrect변수를 선언한다.
- answerIsCorrect 변수에 각 퀴즈에 실제 정답을 가져와 삽입한다.
- 정답과 오답시에 출력문들의 리소스값을 messageId 변수에 삽입한다.
- Snackbar를 이용해 정답인지 오답인지 출력한다.
2. 앱 실행