본문 바로가기

프로그래밍/안드로이드

[Android/Kotlin] DialogFragment 커스텀 대화상자 만들기

이전 글에서는 AlertDialog를 이용해서 기본적인 대화상자를 만들었다.

이번에는 DialogFragment를 이용해서 자신이 원하는 모양의 대화상자를 만들어본다.

 

[Android/Kotlin] Dialog 대화상자 표시 (tistory.com)

 

[Android/Kotlin] Dialog 대화상자 표시

앱을 만들다 보면 가끔 대화상자(Dialog)를 띄워야 할 경우도 있다. (뭔가 확인을 한다던지) 그래서 이번엔 대화상자를 표시하는 방법을 적는다. 대화상자  | Android 개발자  | Android Developers 대화상

mechacat.tistory.com


레이아웃

메인 액티비티의 레이아웃은 저번과 같다.

activity_main.xml

이번에는 DialogFragment로 사용할 레이아웃을 만들어야 한다. 원하는대로 만들면 된다.

dialog_layout.xml
 
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="4dp"
    app:cardCornerRadius="8dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/dial_tv_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="이 앱을 평가해주세요!"
            android:textColor="?android:attr/textColorPrimary"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.492"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/dial_btn_1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="24dp"
            android:text="최고예요"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dial_tv_text" />

        <Button
            android:id="@+id/dial_btn_2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:layout_marginEnd="24dp"
            android:text="별로예요"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.501"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dial_btn_1" />

        <Button
            android:id="@+id/dial_btn_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:layout_marginEnd="24dp"
            android:layout_marginBottom="24dp"
            android:text="다음에 평가할게요"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dial_btn_2" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

dialog_layout.xml

각 버튼의 id는 위에서 부터 'dial_btn_1', 'dial_btn_2', 'dial_btn_3' 로 정했다.

 

DialogFragment 클래스 생성, 액티비티 추가

이제 대화상자 클래스를 만들어야 한다. 프래그먼트를 만드는 법과 같다, Fragment 대신 DialogFragment를 상속한다.

여기서는 버튼을 클릭하면 닫히게 만들었다.

※ 참고로 ViewBinding 사용중이다.

CustomDialog.kt
 
class CustomDialog : DialogFragment() {
    private var _binding: DialogLayoutBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = DialogLayoutBinding.inflate(inflater, container, false)
        val view = binding.root
        // 레이아웃 배경을 투명하게 해줌, 필수 아님
        dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        binding.dialBtn1.setOnClickListener {
            dismiss()    // 대화상자를 닫는 함수
        }
        binding.dialBtn2.setOnClickListener {
            dismiss()
        }
        binding.dialBtn3.setOnClickListener {
            dismiss()
        }

        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

 

액티비티에서 버튼 클릭 이벤트로 대화상자를 호출한다.

MainActivity.kt
 
class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        
        // 버튼 클릭 시 대화상자 표시
        binding.btnDialog.setOnClickListener {
            val dialog = CustomDialog()
            dialog.show(supportFragmentManager, "CustomDialog")
        }
    }
}

실행 결과

 

추가. 대화상자 버튼 클릭 이벤트

리사이클러 뷰처럼 리스너를 이용해서 구현했는데 이렇게 하는게 맞는지 잘 모르겠다. 그래서 코드만 올린다.

CustomDialog.kt
 
class CustomDialog : DialogFragment() {
    private var _binding: DialogLayoutBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = DialogLayoutBinding.inflate(inflater, container, false)
        val view = binding.root
        dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        
        // 각 버튼 클릭 시 각각의 함수 호출
        binding.dialBtn1.setOnClickListener {
            buttonClickListener.onButton1Clicked()
            dismiss()
        }
        binding.dialBtn2.setOnClickListener {
            buttonClickListener.onButton2Clicked()
            dismiss()
        }
        binding.dialBtn3.setOnClickListener {
            buttonClickListener.onButton3Clicked()
            dismiss()
        }

        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
    // 인터페이스
    interface OnButtonClickListener {
        fun onButton1Clicked()
        fun onButton2Clicked()
        fun onButton3Clicked()
    }
    // 클릭 이벤트 설정
    fun setButtonClickListener(buttonClickListener: OnButtonClickListener) {
        this.buttonClickListener = buttonClickListener
    }
    // 클릭 이벤트 실행
    private lateinit var buttonClickListener: OnButtonClickListener
}

 

MainActivity.kt
 
class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.btnDialog.setOnClickListener {
            val dialog = CustomDialog()
            // 버튼 클릭 이벤트 설정
            dialog.setButtonClickListener(object: CustomDialog.OnButtonClickListener{
                override fun onButton1Clicked() {
                    binding.tvText.text = "감사합니다!"
                }

                override fun onButton2Clicked() {
                    binding.tvText.text = "조금 더 노력하겠습니다."
                }

                override fun onButton3Clicked() {
                    binding.tvText.text = "버튼3"
                }
            })
            dialog.show(supportFragmentManager, "CustomDialog")
        }
    }
}

실행 결과