일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 수능
- xcode
- kotlin
- 바른생수
- Android
- 포랩
- 코틀린
- ios
- Firebase
- 수학가형
- 딥러닝
- 내신
- 생명과학
- 수학가형21번
- LineRenderer
- MNIST
- 1등급사과
- 생명과학1
- 모의고사
- 개발일지
- PoLAB
- JavaScript
- customdialog
- 고등학교
- 개발
- Unity
- 플레이스토어
- 유니티
- 과탐
- 고등학생
- Today
- Total
수학적 접근
[Android/Kotlin] Custom Dialog 만들기 (NEW) 본문
이 글에서는 Custom Dialog (Custom Popup)을 만드는 방법을 알아볼 것입니다.
안드로이드에서 기본적으로 제공해주는 다이얼로그가 몇 있지만, 형식이 한정되어 있기 때문에
직접 Dialog를 만들어서 사용하는 것이 자유도가 높고 본인이 제작하고자 하는 앱과 잘 어울릴 것입니다.
이 글에서는 view binding을 이용하여 코드를 작성할 것입니다.
위 공식문서에 따르면, view binding을 사용하기 위해서는 app 수준의 build.gradle
파일에 아래와 같은 내용을 추가해야 합니다.
android {
...
viewBinding {
enabled = true
}
}
위 내용을 추가한 다음 Sync를 해줍시다.
그러고 나서, activity_main.xml
에 다이얼로그를 열 수 있는 Button
과, 다이얼로그에서 받아온 데이터를 적을 TextView
를 만들겠습니다.
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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="다이얼로그 띄우기"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="(Dialog에서 받아온 텍스트)"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
</androidx.constraintlayout.widget.ConstraintLayout>
버튼의 id 는 button
으로, 텍스트뷰의 id는 text
라고 하였습니다.
그리고 activity_main.xml
과 연결되어 있는 MainActivity.kt
파일에 버튼을 불러와서,
onClickListener
까지 연결하는 것까지 우선적으로 해보겠습니다.
package me.dongmin.customdialog_new
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import me.dongmin.customdialog_new.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener(this)
}
override fun onClick(view: View?) {
when(view?.id) {
binding.button.id -> {
}
}
}
}
view binding을 이용하면, 위와 같이 레이아웃의 요소 id의 camel case 형태로 요소들을 호출할 수 있습니다.
(예: 레이아웃에서 id를 @+id/my_text
로 하였다면, view binding에서는 binding.myText
로 호출)
* view binding 사용법을 더 자세히 보려면 더 보기 클릭
액티비티 코드 단에서 view binding을 활용하기 위해서는 아래와 같은 네 가지 구성 요소들을 넣으면 됩니다.
1. import 선언
2. binding 변수 선언
3. binding 인스턴스화
4. setContentView
. . .
import [패키지명].databinding.[레이아웃명의 Pascal Case. 이하 'MyLayout']Binding
. . .
class [클래스명] : AppCompatActivity() {
. . .
private lateinit var binding : MyLayoutBinding
. . .
override fun onCreate(savedInstanceState: Bundle?) {
binding = MyLayoutBinding.inflate(layoutInflator)
setContentView(binding.root)
. . .
}
}
또한, button
에 직접 onClick()
메소드를 구현할 수 있지만, 저는 클래스 단에서 View.OnClickListener
인터페이스를 확장하여 onClick()
메소드를 implement하는 것을 선호합니다.
이제
binding.button.id -> {
}
내부에 Dialog를 띄우는 작업을 할 것입니다.
그 전에 우리가 띄울 Dialog를 xml 파일로 만들겠습니다.
여기서 만들 다이얼로그는 간단하지만 다음과 같은 핵심적인 기능들을 가진 다이얼로그입니다.
1. 부모 액티비티에서 전달한 내용을 다이얼로그에 표시한다.
2. '확인' 버튼을 눌렀을 때에는 다이얼로그가 닫히면서 다이얼로그에서 처리한 결과를 부모 액티비티로 돌려준다.
3. '취소' 버튼을 눌렀을 때에는 아무 동작 없이 다이얼로그가 닫힌다.
my_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="300dp"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="8dp"
>
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="#000000"
android:text="텍스트"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/ok"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:text="확인"/>
<Button
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:text="취소"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
그리고 이 다이얼로그를 나타낼 MyDialog.kt
파일을 작성합니다.
MyDialog.kt
package me.dongmin.customdialog_new
import android.app.Dialog
import android.content.Context
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import me.dongmin.customdialog_new.databinding.MyDialogBinding
class MyDialog(private val context : AppCompatActivity) {
private lateinit var binding : MyDialogBinding
private val dlg = Dialog(context) //부모 액티비티의 context 가 들어감
fun show(content : String) {
binding = MyDialogBinding.inflate(context.layoutInflater)
dlg.requestWindowFeature(Window.FEATURE_NO_TITLE) //타이틀바 제거
dlg.setContentView(binding.root) //다이얼로그에 사용할 xml 파일을 불러옴
dlg.setCancelable(false) //다이얼로그의 바깥 화면을 눌렀을 때 다이얼로그가 닫히지 않도록 함
binding.content.text = content //부모 액티비티에서 전달 받은 텍스트 세팅
//ok 버튼 동작
binding.ok.setOnClickListener {
//TODO: 부모 액티비티로 내용을 돌려주기 위해 작성할 코드
dlg.dismiss()
}
//cancel 버튼 동작
binding.cancel.setOnClickListener {
dlg.dismiss()
}
dlg.show()
}
}
이렇게까지 구현하면 위에서 말한 1번, 3번의 기능은 구현한 것입니다.
부모 액티비티에서 전달한 텍스트가 다이얼로그에 표시되며, 취소 버튼을 누르면 다이얼로그가 닫힙니다.
하지만 아직 확인 버튼을 눌렀을 때 부모 액티비티로 결과를 전달하는 것은 구현하지 않았습니다.
이것을 위해서는 다이얼로그에 콜백 인터페이스를 구현하여야 합니다.
MyDialog
클래스 내부의 아래쪽에 다음과 같이 작성합니다.
MyDialog.kt 에 MyDialogOKClickedListener 인터페이스 작성
. . .
class MyDialog(private val context : AppCompatActivity) {
. . .
fun show(content : String) {
. . .
}
interface MyDialogOKClickedListener {
fun onOKClicked(content : String)
}
}
그리고 아래와 같은 함수를 작성하여, 부모 액티비티에서 부모 액티비티가 실행할 메소드를 등록할 수 있게 합니다.
MyDialog.kt 에 listener 선언 및 setOnOKClickedListener 메서드 작성
. . .
class MyDialog(private val context : AppCompatActivity) {
. . .
private lateinit var listener : MyDialogOKClickedListener
fun show(content : String) {
. . .
}
fun setOnOKClickedListener(listener: (String) -> Unit) {
this.listener = object: MyDialogOKClickedListener {
override fun onOKClicked(content: String) {
listener(content)
}
}
}
interface MyDialogOKClickedListener {
fun onOKClicked(content : String)
}
}
그리고 확인 버튼을 클릭했을 때, onOKClicked()
메소드를 호출할 수 있도록 합니다.
MyDialog.kt 의 btnOK.setOnClickListener 수정
binding.ok.setOnClickListener {
listener.onOKClicked("확인을 눌렀습니다")
dlg.dismiss()
}
마지막으로,MainActivity.kt
의 onClick()
메소드의 button.id
부분을 변경합니다.
MainActivity.kt 의 binding.button.id 부분 수정
binding.button.id -> {
val dlg = MyDialog(this)
dlg.setOnOKClickedListener{ content ->
binding.text.text = content
}
dlg.show("메인의 내용을 변경할까요?")
}
이상을 종합한 MainActivity.kt
코드와 MyDialog.kt
코드는 아래와 같습니다.
MainActivity.kt
package me.dongmin.customdialog_new
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import me.dongmin.customdialog_new.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.button.setOnClickListener(this)
}
override fun onClick(view: View?) {
when(view?.id) {
binding.button.id -> {
val dlg = MyDialog(this)
dlg.setOnOKClickedListener{ content ->
binding.text.text = content
}
dlg.show("메인의 내용을 변경할까요?")
}
}
}
}
MyDialog.kt
package me.dongmin.customdialog_new
import android.app.Dialog
import android.content.Context
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import me.dongmin.customdialog_new.databinding.MyDialogBinding
class MyDialog(private val context : AppCompatActivity) {
private lateinit var binding : MyDialogBinding
private val dlg = Dialog(context) //부모 액티비티의 context 가 들어감
private lateinit var listener : MyDialogOKClickedListener
fun show(content : String) {
binding = MyDialogBinding.inflate(context.layoutInflater)
dlg.requestWindowFeature(Window.FEATURE_NO_TITLE) //타이틀바 제거
dlg.setContentView(binding.root) //다이얼로그에 사용할 xml 파일을 불러옴
dlg.setCancelable(false) //다이얼로그의 바깥 화면을 눌렀을 때 다이얼로그가 닫히지 않도록 함
binding.content.text = content //부모 액티비에서 전달 받은 텍스트 세팅
//ok 버튼 동작
binding.ok.setOnClickListener {
listener.onOKClicked("확인을 눌렀습니다.")
dlg.dismiss()
}
//cancel 버튼 동작
binding.cancel.setOnClickListener {
dlg.dismiss()
}
dlg.show()
}
fun setOnOKClickedListener(listener: (String) -> Unit) {
this.listener = object: MyDialogOKClickedListener {
override fun onOKClicked(content: String) {
listener(content)
}
}
}
interface MyDialogOKClickedListener {
fun onOKClicked(content : String)
}
}
이렇게 아래와 같이 반응하는 다이얼로그를 완성했습니다.
이상의 내용을 담은 프로젝트를 github에 올려두겠습니다.
+++++
내가 마시고 있는 생수는 안전한 생수일까?
15년도부터 생수 수질기준 부적합 판정을 받은 이력을 확인할 수 있는 앱, <바른생수>를 출시하였습니다.
관심 한번씩만 부탁드립니다 ^^
'개발 > Android' 카테고리의 다른 글
[Android/Kotlin] XML Data Binding (0) | 2022.03.03 |
---|---|
[Android/Kotlin] Custom Dialog 만들기 (3) | 2020.02.07 |