[Android] DialogFragment 사용하기

2 분 소요

🙋‍♀️ DialogFragment?

기존 Dialog와 달리 이름에서 알 수 있듯이 fragment의 한 종류이다. 즉, dialog를 보여주는 데 활용되는 fragment이다.

그렇다면 기존 Dialog와 차이점은 무엇일까?

  • DialogFragment를 활용하면 Fragment의 생명주기를 활용할 수 있다.
    • 기존 Dialog를 활용할 때 Activity가 파괴되더라도 dialog가 존재하여 leaked window crash, IllegalStateException 문제가 발생했다.
    • 따라서 수명 주기 이벤트를 올바르게 처리할 수 있게 된다.

그렇다면 본격적으로 DialogFragment를 활용해보자!!


🙋‍♀️ BaseDialogFragment

우선 dialog 같은 경우, 다양한 곳에서 자주 사용될 것 같아 base dialog를 만들어 두었다.

abstract class BaseDialog<T: ViewBinding> (private val layoutResId: Int) : DialogFragment() {

    private var _binding: T? = null
    protected val binding get() = _binding!!

base fragment이기 때문에 abstract으로 구성하고 viewbinding에 사용될 값을 generic으로 받는다.

또한, 해당 fragment와 연결될 layout을 매개변수로 받는다.

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

fragment의 경우, 화면에 나타나지 않을 때 binding값을 반환해줘야 하기 때문에 binding 변수는 크게 _binding, binding으로 구성한다.

    abstract fun getViewBinding(): T
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        dialog?.apply {
            window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) // dialog가 화면에 떴을 때 배경을 투명하게!
        }

        _binding = getViewBinding()
        return binding.root
    }

generic에서는 binding을 바로 할 수 없기 때문에 해당 DialogFragmentr가 사용될 때 getViewBinding을 구현해 _binding 값이 정의될 수 있도록 하였다.

    override fun onResume() {
        super.onResume()

        // 디바이스의 size 얻기
        val display = resources.displayMetrics
        // 비율로 너비 지정
        val window: Window = dialog?.window ?: return
        val params: WindowManager.LayoutParams = window.attributes
        params.width = (display.widthPixels * 0.8).toInt()
        //적용
        dialog?.window!!.attributes = params
    }

dialog의 layout은 기본적으로 match_parent의 너비를 가지게 된다. 따라서 onResume에서 이에 대한 처리가 필요하다!

따라서 디스플레이의 사이즈를 얻고 그에 따른 비율로 너비를 지정해주었다.

이렇게 해서 BaseDialog를 만들었다! 그렇다면 이를 활용해 실제 사용할 dialog를 구현해보자!!


🙋‍♀️ BaseDialog 활용하기

class HomePermissionDialog : BaseDialog<FragmentHomePermissionDialogBinding>(R.layout.fragment_home_permission_dialog) {

위에서 정의한 BaseDialogFragment를 활용해 사용할 Dialog를 구성한다.

여기서 generic으로 viewbindg 값을 지정하고, 연결될 layout을 매개변수로 넘겨준다.

override fun getViewBinding() = FragmentHomePermissionDialogBinding.inflate(layoutInflater)

generic으로 바로 사용하지 못했던 viewbinding을 지정하기 위해 getViewBinding을 구현해 정의해준다.

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        binding.dialogCameraBtn.setOnClickListener {
            dismiss() // dialog 종료
        }

        return binding.root
    }

onCreateView를 override해 버튼의 클릭 리스너 등의 view 작업을 진행한다.

여기서 dismiss는 dialog를 종료시키는 코드이다. 이때 사용할 수 있는 코드가 cancel과 dismiss, 두가지가 존재한다. 이 둘의 차이점은 해당 블로그를 통해 자세히 알 수 있으니 참고 바란다!

여기까지 진행한다면 모든 작업이 마무리된다!!

(주절주절)사실 나는 base를 생성해본 적이 한 번도 없다…ㅎㅎㅎ 지금 개발을 진행하면서 한 레포를 참고하고 있는 데! 생각보다 훨씬 많은 것을 배우고 있는 것 같다!! 오랜만에 블로그를 작성하니 역시 기록이 학습을 되새기는 방식으로는 짱이라는 것을 다시 한 번 느낀다. 앞으로 달려보자! 아자아자!!(주절주절)


🙇‍♀️ 부족한 부분이 있다면 말씀해주세요! 감사합니다!


📃참고

댓글남기기