본문 바로가기
개발

안드로이드 커스텀 다이얼로그 만들기

by 마스터누누 2020. 6. 14.
728x90
반응형

다이얼로그?

다이얼로그는 기존의 화면 위에 떠서 유저에게 간단한 알림을 보내고 싶을 때 사용한다. 안드로이드에서는 AlertDialog라는 다이얼로그를 제공해주지만, 이 경우 기본적인 모양에서 다른 기능을 추가하거나 디자인 변경이 어렵다. 따라서 나에게 필요한 기능과 디자인을 xml으로 생성하고, DialogFragment으로 커스텀 다이얼로그를 만드는 방법에 대해 알아보도록 하자.

 

다이얼로그 예제 완성

예제는 코드는 코틀린으로 작성되었으며, 기본적인 동작을 보여 주기 위해 Data Binding이나 Observer, ViewModel 등을 사용하지 않았다.

 

다이얼로그 코드(xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="20dp">

        <TextView
            android:id="@+id/text_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:textAlignment="center"
            android:textColor="#000000"
            android:textSize="24sp"
            tools:text="타이틀" />

        <TextView
            android:id="@+id/text_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="40dp"
            android:textAlignment="center"
            android:paddingHorizontal="10dp"
            android:textColor="#000000"
            android:textSize="16sp"
            tools:text="설명" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_negative"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#cccccc"
                android:textStyle="bold"
                tools:text="취소" />

            <Button
                android:id="@+id/btn_positive"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#189ae0"
                android:textColor="@android:color/white"
                android:textStyle="bold"
                tools:text="확인" />

        </LinearLayout>

    </LinearLayout>

</RelativeLayout>

 

위의 예제 완성본과 동일한 xml 코드이다. 이때 최상위 layout은 Relative Layout으로 지정해주어야 한다.

tools: 는 미리 보기에서 해당 속성 값을 변경하는 키워드이므로, 동적으로 데이터가 연결될 때나, 특정 케이스의 디자인을 확인할 때 상당히 유용하다. 

 

xml을 inflate 하는 클래스에서 text값과 onClickListener를 직접 연결해줄 것이므로, 모든 요소에 id 값을 부여하자.

 

다이얼로그 코드(Kotlin)

class CustomDialog : DialogFragment() {

    var title: String? = null

    var description: String? = null

    var positiveBtnText: String? = null

    var negativeBtnText: String? = null

    var listener: CustomDialogListener? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        val view = inflater.inflate(R.layout.dialog_custom, container, false)
        return view.rootView
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        view?.apply {
            findViewById<TextView>(R.id.text_title)?.text = title
            findViewById<TextView>(R.id.text_description)?.text = description
            findViewById<Button>(R.id.btn_negative)?.text = negativeBtnText
            findViewById<Button>(R.id.btn_negative)?.setOnClickListener {
                dismiss()
                listener?.onClickPositiveBtn()
            }

            findViewById<Button>(R.id.btn_positive)?.text = positiveBtnText
            findViewById<Button>(R.id.btn_positive)?.setOnClickListener {
                dismiss()
                listener?.onClickNegativeBtn()
            }
        }
    }

    class CustomDialogBuilder {

        private val dialog = CustomDialog()

        fun setTitle(title: String): CustomDialogBuilder {
            dialog.title = title
            return this
        }

        fun setDescription(description: String): CustomDialogBuilder {
            dialog.description = description
            return this
        }

        fun setPositiveBtnText(text: String): CustomDialogBuilder {
            dialog.positiveBtnText = text
            return this
        }

        fun setNegativeBtnText(text: String): CustomDialogBuilder {
            dialog.negativeBtnText = text
            return this
        }

        fun setBtnClickListener(listener: CustomDialogListener): CustomDialogBuilder {
            dialog.listener = listener
            return this
        }

        fun create(): CustomDialog {
            return dialog
        }
    }
}

 

다음과 같은 5개의 요소가 들어간다.

- Title

- Description

- Negative button

- Positive button

- Button click listener

 

다이얼로그를 만드는 생성자에서 모든 파라미터를 받아올 수도 있지만, 예제는 빌더 패턴을 사용했다. 

빌더 패턴은 객체를 만드는 요소를 하나씩 받아 최종적으로 목표 객체의 인스턴스를 빌더가 반환하는 패턴이다. 예제에는 반영되지 않았지만, 불필요한 파라미터를 받지 않을 수 있으며, 파라미터의 추가 변경이 용이하고, 외부에서 목표 객체에 대한 접근이 제한적인 것 등이 장점이다.

 

Main Activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click" />

</LinearLayout>

 

메인 화면 xml에서는 단순하게 테스트를 위한 버튼 하나만 넣었다. 마찬가지로 Main Activity에서 해당 버튼의 onClickListner를 연결해 줄 것이므로 id를 부여하자.

 

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.button).setOnClickListener {
            val dialog = CustomDialog.CustomDialogBuilder()
                .setTitle("환영합니다")
                .setDescription("안녕하세요. 회원님의 접속을 환영합니다.")
                .setPositiveBtnText("확인")
                .setNegativeBtnText("취소")
                .setBtnClickListener(object : CustomDialogListener {
                    override fun onClickPositiveBtn() {
                        // 확인 버튼 클릭 시
                    }

                    override fun onClickNegativeBtn() {
                        // 취소 버튼 클릭 시
                    }
                })
                .create()
            dialog.show(supportFragmentManager, dialog.tag)
        }
    }
}

 

그리고 MainActivity에서는 CustomDialogBuilder를 사용하여 자신이 원하는 문구와 리스너 로직을 직접 넣어서 다이얼로그를 생성할 수 있다. set 함수로 파라미터를 전달하고 create를 호출하면 내가 넣은 파라미터를 기반으로 CustomDialog 인스턴스가 생성된다.

 

앱 실행

첫 실행
버튼 클릭시 다이얼로그 노출

 

 

 

반응형

댓글