[Android] Dialog Fragment Custom

Twaun·2022년 7월 27일
0

Android

목록 보기
17/24

Dialog Fragment 이란?

Fragment를 상속하면서 대화상자 구현할 때 사용되도록 권장되고 있다. 프래그먼트를 다이얼로그 처럼 사용할 수 있고, 프래그먼트의 생명주기를 사용할 수 있다.

사용 방법

안드로이드에서 제공하는 Alert Dialog 가 아닌 새로운 Custom 뷰를 만들고 싶었다. layout을 fragment에서 바인딩에서 사용하는 것과 같이 사용할 수 있었다.

XML

다음과 같이 FrameLayout으로 감싸서 원하는 뷰를 그려주면 된다.

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <androidx.constraintlayout.widget.ConstraintLayout
			android:layout_width="match_parent"
            android:layout_height="match_parent">
		
        	<androidx.constraintlayout.widget.ConstraintLayout
				android:layout_width="0dp"
                android:layout_height="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintDimensionRatio="H, 5:4"
				app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.5"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintWidth_percent="0.8">
			</androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

Base Dialog

Base Fragment와 Base Activity 처럼 Dialog도 Base Dialog를 만들어서 사용하면 좋을 것 같아서 DialogFragment()를 상속하고 바인딩처리 까지 하는 Base Dialog를 만들어보았다.

abstract class BaseDialog<VB: ViewDataBinding>(@LayoutRes private val layoutId: Int) : DialogFragment() {

    protected var _binding: VB? = null
    val binding: VB
        get() = _binding ?: throw IllegalStateException("binding fail")

	// 버튼이 한개인지 두개인지
    enum class ButtonType{
        ONE, TWO
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NO_TITLE, R.style.my_dialog)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = DataBindingUtil.inflate(inflater, layoutId, container, false)
        binding.lifecycleOwner = viewLifecycleOwner
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()
        setEvent()
    }

    open fun initView() {}
    open fun setEvent() {}

}

dialog style

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="my_dialog" parent="Theme.AppCompat.Dialog">

        <item name="android:windowIsFloating">false</item>
        <item name="android:windowFullscreen">false</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:backgroundDimAmount">1</item>

    </style>
</resources>

Common Dialog

앱에 전반적으로 쓰인 공통 다이얼로그를 만들어보자!!
위에서 만든 BaseDialog를 상속하면서 제목과, 메세지, 버튼 개수와 콜백을 파라미터로 받는 클래스이다.

다음과 같이 콜백처리를 했을 때 메모리릭에 문제가 생길 수 있을지 아직 모르겠다..

class CommonDialog(
    private val buttonType: ButtonType,
    private val content: DialogBody,
    private var onCancelListener : (()->Unit)? = null,
    private var onConfirmListener : (()->Unit)? = null
) : BaseDialog<FragmentDialogCommonBinding>(R.layout.fragment_dialog_common){

    override fun initView() {
        super.initView()

		// 버튼 타입에 따른 버튼 모양
        when(buttonType) {
            ButtonType.ONE -> {
                binding.layoutBottomTypeOne.visible()
            }
            ButtonType.TWO -> {
                binding.layoutBottomTypeTwo.visible()
            }
        }

		// 타이틀, 메세지 전달
        content.run {
            binding.tvTitle.text = title
            binding.tvMessage.text = message ?: ""
        }
    }

	// 클릭 이벤트
    override fun setEvent() {
        super.setEvent()

        binding.btnCancelTypeTwo.setOnSingleClickListener {
            onCancelListener?.invoke()
            dismiss()
        }
        binding.btnCompleteTypeTwo.setOnSingleClickListener {
            onConfirmListener?.invoke()
            dismiss()
        }
        binding.btnCompleteTypeOne.setOnSingleClickListener {
            onConfirmListener?.invoke()
            dismiss()
        }
    }
}

Dialog 띄우기

show(fragmentManager, tag) 메서드 호출을 통해서 DialogFragment를 현재 화면에 띄울 수 있다.

CommonDialog(
	BaseDialog.ButtonType.TWO,
	DialogBody("제목", "내용"),
    {
    	// onCancelListener
    }, {
		// onConfirmListener
	}).show(childFragmentManager, null)

위와 가이 BaseDialog와 이를 상속한 Dialog를 만들어 사용해봤는데 실전 프로젝트에 계속 사용해보면서 더 나은 방법이 있으면 업데이트 할 예정이다.

profile
Android Developer

0개의 댓글