[오늘 배운 내용]
-1- DIalog
- 다이얼로그란 사용자에게 결정을 내리거나 추가 정보를 입력하라는 등 메세지를 표시하는 창이다.
- 다이얼로그는 보통 화면을 가득 채우지 않고, 사용자가 다음으로 진행하기 전에 조치를 취해야 하는 이벤트에 사용된다.
- 일반적으로 AlertDialog을 사용하며, AlertDialog Android 앱의 메세지, 옵션, 버튼이 포함된 Dialog를 표시할 수 있다.
- 기본형식의 AlertDialog 는 제목한개, 버튼 최대 세개, 선택 가능한 항목의 목록 또는 맞춤 레이아웃 한 개를 표시할 수 있는 Dialog이다.
- AlertDialog의 하위 클래스로 특정 날짜 및 시간 Dialog 창을 띄워주는 DatePickerDialog, TimePickerDialog가 있다. 각각 날짜, 시간 Dialog를 띄워주는 클래스이다.
- AlertDialog및 하위 클래스로 만들 수 있는 Dialog 버튼을 클릭하면 해당 Dialog창이 나오며, Dialog의 상호작용이 MainActivity 상단 TextView에 반영이 되도록 지정.
- xml
<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">
<TextView
android:id="@+id/tv_Title"
android:layout_width="200dp"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_dialog"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_custom"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="custom dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_dialog" />
<Button
android:id="@+id/btn_data"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="Date picker dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_custom" />
<Button
android:id="@+id/btn_time"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="Time picker dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_data" />
<Button
android:id="@+id/btn_grogress"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="progress dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_time" />
</androidx.constraintlayout.widget.ConstraintLayout>
- 기본 Dialog
binding.btnDialog.setOnClickListener {
var builder = AlertDialog.Builder(this)
builder.setTitle("기본 다이얼로그 타이틀")
builder.setMessage("기본 다이얼로그 메세지")
builder.setIcon(R.drawable.ic_android_black_24dp)
val listener = object : DialogInterface.OnClickListener {
override fun onClick(p0: DialogInterface?, p1: Int) {
when (p1) {
DialogInterface.BUTTON_POSITIVE ->
binding.tvTitle.text = "BUTTON_POSITIVE"
DialogInterface.BUTTON_NEGATIVE ->
binding.tvTitle.text = "BUTTON_NEGATIVE"
DialogInterface.BUTTON_NEUTRAL ->
binding.tvTitle.text = "BUTTON_NEUTRAL"
}
}
}
builder.setPositiveButton("Positive",listener)
builder.setNegativeButton("Negative",listener)
builder.setNeutralButton("Neutral",listener)
builder.show()
}
- Dialog에서 Positive 선택 시 상단 TextView 텍스트 변경
- 커스텀 Dialog
- 커스텀 Dialog는 내가 Dialog에 나타날 UI를 직접 만들어서 Dialog 창을 띄울 수 있다.
binding.btnCustom.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("Add Contact")
builder.setIcon(R.drawable.ic_android_black_24dp)
val v1 = layoutInflater.inflate(R.layout.dialog, null)
builder.setView(v1)
val lister = DialogInterface.OnClickListener { p0, p1 ->
val alert = p0 as AlertDialog
val edit1: EditText? = alert.findViewById<EditText>(R.id.edit_InputName)
val edit2: EditText? = alert.findViewById<EditText>(R.id.edit_InputNumber)
edit2?.addTextChangedListener(PhoneNumberFormattingTextWatcher())
binding.tvTitle.text = "이름 : ${edit1?.text}"
binding.tvTitle.append(" / 번호 : ${edit2?.text}")
}
builder.setPositiveButton("확인",lister)
builder.setNegativeButton("취소", null)
builder.show()
}
- 날짜 및 시간 Dialog
- 각각 DatePickerDialog, TimePickerDialog를 사용하지만 Calendar 를 getInstance() 해서 사용하는 방법이 같다.
- DatePickerDialog
// 날짜 Dialog
binding.btnData.setOnClickListener {
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
val listener = DatePickerDialog.OnDateSetListener { datePicker, i, i2, i3 ->
binding.tvTitle.text = "$i 년 ${i2 + 1}월 $i3 일"
}
val picker = DatePickerDialog(this,listener,year,month,day)
picker.show()
}
- TimePickerDialog
// 시간 Dialog
binding.btnTime.setOnClickListener {
val calendar = Calendar.getInstance()
val hour = calendar.get(Calendar.HOUR)
val minute = calendar.get(Calendar.MINUTE)
val listener = TimePickerDialog.OnTimeSetListener { timePicker, i, i2 ->
binding.tvTitle.text = "$i 시 $i2 분"
}
val timePicker = TimePickerDialog(this,listener,hour,minute,true) // 17시 등 24시제
timePicker.show()
}
- PrgressBar Dialog
- progressbar.xml 을 생성해서 직접 progressbar UI를 생성해주고 해당 진행바를 Dialog에 띄워주는 것
- progressbar.xml 의 palette에서 ProgressBar Item을 기본으로 생성해도 나쁘지 않은 progressbar가 생성된다.
<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">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="60dp"
android:layout_height="60dp"
android:indeterminate="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
- progressDialog main.kt
binding.btnProgress.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("프로그래스바")
builder.setIcon(R.drawable.ic_android_black_24dp)
val v1 = layoutInflater.inflate(R.layout.progressbar,null)
builder.setView(v1)
builder.show()
}
-2- 알림 (Notification)
- 알림은 알림음, 진동, 화면내의 별도의 이벤트(예시 : 카카오톡의 화면 상단에 알림창)등을 통해 사용자에게 앱과 관련한 정보를 보여주는 기능이다.
- 이 알림들은 상단 상태바(Statusbar)에 표시되기도 하고, 없애고 싶은 앱 아이콘의 뱃지, 상태바를 내리면 보이는 화면을 통해 알림창에 표시되며 간단한 작업 또는 알림을 터치하여 해당 앱을 들어갈 수도 있다.
- 알림을 생성하는 방법
- Android 8.0 이상에서는 알림채널을 먼저 생성해야한다.
- 알림채널은 알림을 그룹화하여 중요도를 설정하거나, 알림의 활성화 상태( ON / OFF ) 등을 변경할 수 있다.
- 알림채널 생성
fun notification() {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val builder: NotificationCompat.Builder
// 8.0 버전인 Oreo Code의 O 이상일 경우 알림채널 생성.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "one-channel"
val channelName = "My Channel One"
val channel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "My Channel One Description"
// 앱 아이콘 뱃지에 표시.
setShowBadge(true)
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) // RingtonManager로 효과음 가져오기
val audioAttributes = AudioAttributes
// 빌더 클래스의 인스턴스를 가져와 속성을 설정.
.Builder()
// 알림이 어떤식으로 사용되는지 설정. - sonification 타입은 버튼,이벤트 등으로 사용자가 직접 상호작용하는 타입
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
// 알림(Notification) 소리의 크기를 Alarm 소리의 크기로 설정
.setUsage(AudioAttributes.USAGE_ALARM)
.build() // 설정한 속성을기반으로 AudioAttributes 객체를 빌드하여 반환함.
setSound(uri, audioAttributes) // uri로 설정한 알림음, audioAtrributes의 볼륨설정 적용.
// 진동 설정
enableVibration(true)
}
manager.createNotificationChannel(channel)
builder = NotificationCompat.Builder(this, channelId)
} else {
builder = NotificationCompat.Builder(this)
}
- 알림 내용 설정 및 기능 설정
// 이미지 리소스를 알림창에 들어갈 사이즈로 만듦
val bitMap = BitmapFactory.decodeResource(resources, R.drawable.cavempt)
// 특정 화면으로 넘어가게 하기 위해 Intent 설정.
val intent = Intent(this, SecondActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 알림에 보여질 내용 설정.
builder.run {
setSmallIcon(R.drawable.ic_android_black_24dp)
setWhen(System.currentTimeMillis())
setContentTitle("새로움 알림입니다")
setContentText("알림 내용입니다")
setStyle(
NotificationCompat.BigTextStyle()
.bigText(
"긴 텍스트 내용 아무거나 적는다. 오늘 점심은 돈까스를 먹고 점심 먹고 난 뒤로 아메리카노 500ml 2잔 마셨다 " +
"긴 텍스트 내용 아무거나 적는다. 오늘 점심은 돈까스를 먹고 점심 먹고 난 뒤로 아메리카노 500ml 2잔 마셨다"
)
)
setLargeIcon(bitMap)
addAction(R.mipmap.ic_launcher, "Action", pendingIntent)
}
manager.notify(11, builder.build()) // 위에서 작성한 코드를 알림에 적용시키고, 알림 띄우기
}
}
- 알림창 화면
-3- Intent FLAG
- Intent 의 동작을 제어하기 위해 FLAG가 있다.
- Intent flag를 왜 사용하는가?
- 안드로이드에서 Activity를 호출하다보면 발생하는 Activity의 중복문제나 흐름을 제어해주고 싶을 때 사용
- Task
- Task는 Stack 구조로 되어 있으며 앱에서 Activity들을 보관하고 관리한다.
- ACTIVITIY_NEW_TASK
- 해당 플래그는 시작되는 액티비티에 대한 새 작업(백 스택)을 생성하는 데 사용된다. 동일한 동일한 앱을 가진 작업이 존재하는 경우 대상 액티비티가 해당 작업 내에서 포그라운드로 이동된다. 해당 작업이 없으면 액티비티에 대한 새 작업이 생성된다.
- ACTIVITY_CLEAR_TASK
- ACTIVITY_NEW_TASK와 함께 사용되며 새 액티비티가 작업의 루트에 있어야하고, 스택에서 그 위에 있는 모든 액티비티가 제거되어야 함을 나타낸다. 이는 백 스택에서 이전 화면을 모두 제거하면서 사용자를 앱의 초기 화면으로 이동시키는 로그아웃 기능을 구현하는데 사용 등.
- ACTIVITY_CLEAR_TOP
- 호출하는 액티비티가 스택에 존재할 경우에, 해당 액티비티를 최상위로 올리면서, 그 위에 존재하던 액티비티 들을 모두 삭제하는 FLAG
- ACTIVITY_SINGLE_TOP
- 호출되는 액티비티가 최상위에 존재할 경우, 해당 액티비티를 다시 생성하지 않고, 존재하던 액티비티를 다시 사용하는 FLAG
[오늘 복습한 내용]
정신없이 강의 듣고 실습하느라 따로 복습으로 생각되는 행위는 하지 못함
[오류,에러 등등]
1. EditText 자동 하이픈 ' - ' 이 안들어감
- addTextChangedListener{PhoneNumberFormattingTextWatcher()} 를 해도 적용이 안되는데 일단 과제들이랑 학습해야하는 부분이 많이 남아서 메모해두고 추후에 수정할 것.
binding.btnCustom.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("Add Contact")
builder.setIcon(R.drawable.ic_android_black_24dp)
val v1 = layoutInflater.inflate(R.layout.dialog, null)
builder.setView(v1)
val lister = DialogInterface.OnClickListener { p0, p1 ->
val alert = p0 as AlertDialog
val edit1: EditText? = alert.findViewById<EditText>(R.id.edit_InputName)
val edit2: EditText? = alert.findViewById<EditText>(R.id.edit_InputNumber)
edit2?.addTextChangedListener(PhoneNumberFormattingTextWatcher())
binding.tvTitle.text = "이름 : ${edit1?.text}"
binding.tvTitle.append(" / 번호 : ${edit2?.text}")
}
builder.setPositiveButton("확인",lister)
builder.setNegativeButton("취소", null)
builder.show()
}
[느낀 점]
1. 어렵다.
2. 코드는 책 읽듯이 좌측 상단부터 천천히 읽어나가자. 요즘 긴 코드를 만나면 읽기 어려운 느낌인데, 윗 줄 부터 천천히 읽어 나가면 금방 이해할 수 있을 것 같다.
3. 학습 속도가 너무 느리다
[Reference]
// 권한요청
https://eunoia3jy.tistory.com/145
// Notification
https://notepad96.tistory.com/205
// FLAG
https://seosh817.tistory.com/14
// BitmapFactory Android.developer
https://developer.android.com/topic/performance/graphics/load-bitmap?hl=ko
// AudioAttributes Android.developer
https://developer.android.com/reference/android/media/AudioAttributes.html#CONTENT_TYPE_SONIFICATION
// RingtoneManager
https://curryyou.tistory.com/380
// AudioAttributes
'TIL' 카테고리의 다른 글
[TIL] Lambda를 이용해 Dialog 분리해서 제어하기, FloatingButton으로 RecyclerView 스크롤 상단으로 이동하기 (0) | 2023.08.31 |
---|---|
[TIL] 뒤로가기 버튼 클릭 이벤트 | putExtra, getParcelableExtra로 데이터 옮기기 (0) | 2023.08.30 |
[TIL] Fragment, Bottom Navigation, System UI isn't responding (0) | 2023.08.25 |
[TIL] RecyclerView (0) | 2023.08.24 |
[TIL] Adapter 활용한 ListView, GridView (0) | 2023.08.23 |