수학적 접근

[Android/Kotlin] Custom Dialog 만들기 본문

개발/Android

[Android/Kotlin] Custom Dialog 만들기

평등수렴 2020. 2. 7. 10:45
반응형

=========================================================

 

22.03.03 기준 최신 코드를 사용하여 새로 글을 작성하였습니다.

 

이 글에서 소개하는 내용은 구 버전 코드로 작성된 내용이므로,

 

아래 링크 글로 이동해주시기 바랍니다!

 

[Android/Kotlin] Custom Dialog 만들기 (NEW)

이 글에서는 Custom Dialog (Custom Popup)을 만드는 방법을 알아볼 것입니다. 안드로이드에서 기본적으로 제공해주는 다이얼로그가 몇 있지만, 형식이 한정되어 있기 때문에 직접 Dialog를 만들어서 사

dkfk2747.tistory.com

 

=========================================================

 

 

이 글에서는 Custom Dialog (Custom Popup)을 만드는 방법을 알아볼 것입니다.

 

 

안드로이드에서 기본적으로 제공해주는 다이얼로그가 몇 있지만, 형식이 한정되어 있기 때문에

 

직접 Dialog를 만들어서 사용하는 것이 자유도가 높고 본인이 제작하고자 하는 앱과 잘 어울릴 것입니다.

 

먼저, 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"
    tools:context=".MainActivity">

    <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="8dp"
        android:textSize="17sp"
        android:textColor="#000000"
        android:text="(Dialog에서 받아온 텍스트)"
        app:layout_constraintEnd_toEndOf="parent"
        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 com.dongmin.www.customdialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), View.OnClickListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        when(v?.id) {
            button.id -> {

            }
        }
    }
}

java에서 kotlin으로 넘어오면서 좋은 점은, 각각의 view를 kt 소스파일에서 다시 정의할 필요없이,

 

xml 파일에 정의된 id를 그대로 변수로 사용할 수 있다는 점입니다.

 

이를 위해서 다음과 같은 선언을 하였습니다.

import kotlinx.android.synthetic.main.activity_main.*

이를 선언하면, activity_main.xml 에 정의된 모든 view들의 id를 그대로 변수로 사용할 수 있습니다.

 

 

또한, button에 직접 onClick() 메소드를 구현할 수 있지만, 저는 클래스 단에서 View.OnClickListener 인터페이스를 확장하여 onClick() 메소드를 implement하는 것을 선호합니다.

 

 

이제

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 com.dongmin.www.customdialog

import android.app.Dialog
import android.content.Context
import android.view.Window
import android.widget.Button
import android.widget.TextView

class MyDialog(context : Context) {
    private val dlg = Dialog(context)   //부모 액티비티의 context 가 들어감
    private lateinit var lblDesc : TextView
    private lateinit var btnOK : Button
    private lateinit var btnCancel : Button
    private lateinit var listener : MyDialogOKClickedListener

    fun start(content : String) {
        dlg.requestWindowFeature(Window.FEATURE_NO_TITLE)   //타이틀바 제거
        dlg.setContentView(R.layout.my_dialog)     //다이얼로그에 사용할 xml 파일을 불러옴
        dlg.setCancelable(false)    //다이얼로그의 바깥 화면을 눌렀을 때 다이얼로그가 닫히지 않도록 함

        lblDesc = dlg.findViewById(R.id.content)
        lblDesc.text = content

        btnOK = dlg.findViewById(R.id.ok)
        btnOK.setOnClickListener {

            //TODO: 부모 액티비티로 내용을 돌려주기 위해 작성할 코드

            dlg.dismiss()
        }

        btnCancel = dlg.findViewById(R.id.cancel)
        btnCancel.setOnClickListener {
            dlg.dismiss()
        }

        dlg.show()
    }

}

이렇게까지 구현하면 위에서 말한 1번, 3번의 기능은 구현한 것입니다.

 

부모 액티비티에서 전달한 텍스트가 다이얼로그에 표시되며, 취소 버튼을 누르면 다이얼로그가 닫힙니다.

 

하지만 아직 확인 버튼을 눌렀을 때 부모 액티비티로 결과를 전달하는 것은 구현하지 않았습니다.

 

이것을 위해서는 다이얼로그에 콜백 인터페이스를 구현하여야 합니다.

 

MyDialog 클래스 내부의 아래쪽에 다음과 같이 작성합니다.

 

 

 

MyDialog.kt 에 MyDialogOKClickedListener 인터페이스 작성

. . .

class MyDialog(context : Context) {
    . . .

    fun start(content : String) {
       . . .
    }

    interface MyDialogOKClickedListener {
        fun onOKClicked(content : String)
    }
}

 

 

 

그리고 아래와 같은 함수를 작성하여, 부모 액티비티에서 부모 액티비티가 실행할 메소드를 등록할 수 있게 합니다.

 

MyDialog.kt 에 listener 선언 및 setOnOKClickedListener 메서드 작성

. . .

private lateinit var listener : MyDialogOKClickedListener

class MyDialog(context : Context) {
    . . .

    fun start(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 수정

btnOK.setOnClickListener {
    listener.onOKClicked("확인을 눌렀습니다")
    dlg.dismiss()
}

 

 

 

마지막으로,MainActivity.ktonClick() 메소드의 button.id 부분을 변경합니다.

MainActivity.kt 의 button.id 부분 수정

button.id -> {
    val dlg = MyDialog(this)
    dlg.setOnOKClickedListener{ content ->
        text.text = content
    }
    dlg.start("메인의 내용을 변경할까요?")
}

 

 

 

 

이상을 종합한 MainActivity.kt 코드와 MyDialog.kt 코드는 아래와 같습니다.

MainActivity.kt

package com.dongmin.www.customdialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), View.OnClickListener{

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        when(v?.id) {
            button.id -> {
                val dlg = MyDialog(this)
                dlg.setOnOKClickedListener{ content ->
                    text.text = content
                }
                dlg.start("메인의 내용을 변경할까요?")
            }
        }
    }
}

MyDialog.kt

package com.dongmin.www.customdialog

import android.app.Dialog
import android.content.Context
import android.view.Window
import android.widget.Button
import android.widget.TextView

class MyDialog(context : Context) {
    private val dlg = Dialog(context)   //부모 액티비티의 context 가 들어감
    private lateinit var lblDesc : TextView
    private lateinit var btnOK : Button
    private lateinit var btnCancel : Button
    private lateinit var listener : MyDialogOKClickedListener

    fun start(content : String) {
        dlg.requestWindowFeature(Window.FEATURE_NO_TITLE)   //타이틀바 제거
        dlg.setContentView(R.layout.my_dialog)     //다이얼로그에 사용할 xml 파일을 불러옴
        dlg.setCancelable(false)    //다이얼로그의 바깥 화면을 눌렀을 때 다이얼로그가 닫히지 않도록 함

        lblDesc = dlg.findViewById(R.id.content)
        lblDesc.text = content

        btnOK = dlg.findViewById(R.id.ok)
        btnOK.setOnClickListener {

            listener.onOKClicked("확인을 눌렀습니다")
            dlg.dismiss()
        }



        btnCancel = dlg.findViewById(R.id.cancel)
        btnCancel.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에 올려두겠습니다.

 

 

dmseo1/dm-tistory-android-customdialog

Contribute to dmseo1/dm-tistory-android-customdialog development by creating an account on GitHub.

github.com

 

 

 

 

+++++

 

내가 마시고 있는 생수는 안전한 생수일까?

15년도부터 생수 수질기준 부적합 판정을 받은 이력을 확인할 수 있는 앱, <바른생수>를 출시하였습니다.

 

관심 한번씩만 부탁드립니다 ^^

 

바로가기!

 

 

반응형

'개발 > Android' 카테고리의 다른 글

[Android/Kotlin] XML Data Binding  (0) 2022.03.03
[Android/Kotlin] Custom Dialog 만들기 (NEW)  (1) 2022.03.03
Comments