오늘은 비밀번호를 저장하는 기능과 변경하는 기능을 구현해볼 것이다.
또한, 다이어리 내용을 앱이 종료되더라도 기기에 저장하는 기능을 구현할 것이다.
SharedPreference의 속성들과 사용하는 법
Custom Font 사용하기
Handler 사용하기
Theme 사용하기
AlertDialog 사용하기
📌 알게 된 점
1. ActionBar를 없애려면 theme 파일에 테마 설정을 해주고, manifast 파일에 표시해줘야 한다.
2. Custom Font 사용하는 법
font 이름을 가진 디렉터리를 만들어준다.
원하는 폰트를 다운 받은 다음, font 디렉터리에 넣어주고 fontFamily를 설정해준다.
참고로, 폰트 파일 이름은 첫문자가 소문자로 시작되어야 한다!
3. handler라는 것은 thread와 thread 간에 통신을 엮어주는 안드로이드에서 제공하는 기능이다.
📌 최종 코드
- Activity
MainActivity.kt
package com.example.secretdiary
import android.content.Context
import android.content.Intent
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.NumberPicker
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatButton
import androidx.core.content.edit
class MainActivity : AppCompatActivity() {
private val numberPicker1: NumberPicker by lazy {
findViewById<NumberPicker>(R.id.numberPicker1)
.apply {
minValue = 0
maxValue = 9
}
}
private val numberPicker2: NumberPicker by lazy {
findViewById<NumberPicker>(R.id.numberPicker2)
.apply {
minValue = 0
maxValue = 9
}
}
private val numberPicker3: NumberPicker by lazy {
findViewById<NumberPicker>(R.id.numberPicker3)
.apply {
minValue = 0
maxValue = 9
}
}
private val openButton: AppCompatButton by lazy {
findViewById<AppCompatButton>(R.id.openButton)
}
private val changePasswordButton: AppCompatButton by lazy {
findViewById<AppCompatButton>(R.id.changePasswordButton)
}
private var changePasswordMode = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
numberPicker1
numberPicker2
numberPicker3
openButton.setOnClickListener {
if (changePasswordMode) {
Toast.makeText(this, "비밀번호 변경 중입니다.", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val passwordPreferences = getSharedPreferences("password", MODE_PRIVATE)
val passwordFromUser =
"${numberPicker1.value}${numberPicker2.value}${numberPicker3.value}"
// 초기 비밀번호
if (passwordPreferences.getString("password", "000").equals(passwordFromUser)) {
startActivity(Intent(this, DiaryActivity::class.java))
} else {
showErrorAlertDialog()
}
}
changePasswordButton.setOnClickListener {
val passwordPreferences = getSharedPreferences("password", MODE_PRIVATE)
val passwordFromUser =
"${numberPicker1.value}${numberPicker2.value}${numberPicker3.value}"
if (changePasswordMode) { //번호를 저장하는 기능
passwordPreferences.edit(true) {
putString("password", passwordFromUser)
}
changePasswordButton.setBackgroundColor(Color.BLACK)
changePasswordMode = false
} else { // changePassWordMode 가 활성화 :: 비밀번호가 맞는지 체크
// 초기 비밀번호
if (passwordPreferences.getString("password", "000").equals(passwordFromUser)) {
changePasswordMode = true
Toast.makeText(this, "변경할 패스워드를 입력해주세요", Toast.LENGTH_SHORT).show()
changePasswordButton.setBackgroundColor(Color.RED)
} else {
showErrorAlertDialog()
}
}
}
}
private fun showErrorAlertDialog() {
AlertDialog.Builder(this)
.setTitle("실패")
.setMessage("비밀번호가 잘못되었습니다.")
.setPositiveButton("확인") { dialog, which -> }
.create()
.show()
}
}
DiaryActivity.kt
package com.example.secretdiary
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.core.widget.addTextChangedListener
class DiaryActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_diary)
val diaryEditText = findViewById<EditText>(R.id.diaryEditText)
val detailPreferences = getSharedPreferences("diary", Context.MODE_PRIVATE)
diaryEditText.setText(detailPreferences.getString("detail", ""))
val runnable = Runnable {
getSharedPreferences("diary", Context.MODE_PRIVATE).edit {
putString("detail", diaryEditText.text.toString())
}
Log.d("DiaryActivity", "SAVE!!!! ${diaryEditText.text.toString()}")
}
diaryEditText.addTextChangedListener {
Log.d("DiaryActivity", "TextChanged :: $it")
handler.removeCallbacks(runnable) // 이전 값 지우기
handler.postDelayed(runnable, 500) // 0.5초 뒤에 실행
}
}
}
- Layout
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"
android:background="#3f51b5"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:fontFamily="@font/poor_story"
android:text="The Secret Garden"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/passwordLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/passwordLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#cdcdcd"
android:padding="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/openButton"
android:layout_width="40dp"
android:layout_height="60dp"
android:layout_marginEnd="10dp"
android:background="#a3a3a3"
app:layout_constraintBottom_toBottomOf="@id/numberPicker1"
app:layout_constraintEnd_toStartOf="@id/numberPicker1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/numberPicker1" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/changePasswordButton"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginTop="10dp"
android:background="@color/black"
app:layout_constraintEnd_toEndOf="@id/openButton"
app:layout_constraintStart_toStartOf="@+id/openButton"
app:layout_constraintTop_toBottomOf="@id/openButton" />
<NumberPicker
android:id="@+id/numberPicker1"
android:layout_width="30dp"
android:layout_height="120dp"
android:background="#a3a3a3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/numberPicker2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/openButton"
app:layout_constraintTop_toTopOf="parent" />
<NumberPicker
android:id="@+id/numberPicker2"
android:layout_width="30dp"
android:layout_height="120dp"
android:background="#a3a3a3"
app:layout_constraintEnd_toStartOf="@id/numberPicker3"
app:layout_constraintStart_toEndOf="@id/numberPicker1"
app:layout_constraintTop_toTopOf="@id/numberPicker1" />
<NumberPicker
android:id="@+id/numberPicker3"
android:layout_width="30dp"
android:layout_height="120dp"
android:background="#a3a3a3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/numberPicker2"
app:layout_constraintTop_toTopOf="@id/numberPicker1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
activity_diary.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#3f51b5"
android:padding="24dp">
<EditText
android:id="@+id/diaryEditText"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/white"
android:gravity="start|top"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
'🍞 Front-End > Android' 카테고리의 다른 글
[Android] 계산기 RoomDB (0) | 2022.10.31 |
---|---|
[Android] 에뮬레이터에서 Toast 메세지가 안 보일 때 (0) | 2022.10.31 |
[Android] 로또 번호 추첨기 (2) | 2022.10.27 |
[Android] BMI 계산기 (0) | 2022.10.27 |
[Android] 안드로이드 리사이클러뷰(RecyclerView) (0) | 2022.10.23 |