Android 다이얼로그 2 : 알림창, 커스텀 다이얼로그

timothy jeong·2021년 11월 4일
0

Android with Kotlin

목록 보기
16/69

알림 창 띄우기

안드로이드에서 다이얼로그의 기본은 AlertDialog 이다. 알림창은 단순히 메시지만 출력할 수도 있고 다양한 화면을 출력할 수도 있다. 이전에 살펴본 데이트 피커, 타임 피커 모두 AlertDialog 의 하위 클래스이다.

알림창은 크게 제목, 내용, 버튼 영역 이라는 3가지 영역으로 구분된다. AlertDialog 의 생성자는 protected 로 막혀있기 때문에 Builder 를 대신 사용해야한다.

기본 알림창

버튼없이 아이콘, 제목, 이름으로 구성된 알림 창을 띄우려면 아래와 같이 만들면 된다.

button2.setOnClickListener {
            AlertDialog.Builder(this)
                .setIcon(android.R.drawable.ic_dialog_info)
                .setTitle("Hello")
                .setMessage("Bye")
                .show()
        }

버튼 추가 알림 창

버튼 영역을 추가하기 위해서는 setPositiveButton(text , listener), setNegativeButton(text , listener), setNeutralButton(text , listener) 세개를 이용할 수 있다. 똑같은 버튼을 중복해서 쓰면 하나만 나타난다. 따라서 이 포맷에서 알림 창에 추가할 수 있는 버튼은 3개이다.

        button2.setOnClickListener {
            AlertDialog.Builder(this)
                .setIcon(android.R.drawable.ic_dialog_info)
                .setTitle("Hello")
                .setMessage("Bye")
                .setPositiveButton("Yes", null)
                .setNegativeButton("No", null)
                .setNeutralButton("More", null)
                .show()
        }

모두 똑같은 버튼인데 굳이 세개의 함수로 나눠놓아야 하는 이유가 있을까? 이벤트 핸들러에서 어떤 버튼이 눌렸는지 구분하기 위해서 나눠놓았다. 각 이벤트에 해당하는 이벤트 핸들러를 따로 만들 수도 있지만, 한 알림 창의 버튼 이벤트를 하나의 이벤트 핸들러에서 모두 처리할 수도 있다. 이때 어떤 버튼이 눌렸는지 구분해야 하는데, 셋 중 어떤 함수를 사용했는지에 따라 이벤트 핸들러에 전달되는 매개변숫값이 달라서 그 값으로 구분한다.

    val eventHandler = DialogInterface.OnClickListener { dialog, which ->
        when (which) {
            DialogInterface.BUTTON_POSITIVE -> Log.d("Info", "positive button")
            DialogInterface.BUTTON_NEGATIVE -> Log.d("Info", "negative button")
            DialogInterface.BUTTON_NEUTRAL -> Log.d("Info", "neutral button")
        }
    }
    
        button2.setOnClickListener {
            AlertDialog.Builder(this)
                .setIcon(android.R.drawable.ic_dialog_info)
                .setTitle("Hello")
                .setMessage("Bye")
                .setPositiveButton("Yes", eventHandler)
                .setNegativeButton("No", eventHandler)
                .setNeutralButton("More", eventHandler)
                .show()
        }

선택지 알림창

만약 목록을 제공하고 이 중 하나를 선택 받는 알림 창을 만들고자 한다면 아래의 함수를 이용한다.

// 알림창에 보여줄 목록
setItems(items: ArrayOf<SCharSequence!>!, listener: DialogInterface.OnClickListener): AlerDialog.Builder!

// 알림창에 목록과 체크박스를 보여주고, checkItems 파마리터를 통해 선택된 목록들을 확인할 수 있음.
setMultiChoiceItems(items: ArrayOf<SCharSequence!>!, checkItems: BooleaenArray!, listener: DialogInterface.OnClickListener): AlerDialog.Builder!): AlerDialog.Builder!

// 알림창에 목록을 보여주고, checkItem 파마리터를 통해 선택된 하나의 목록 확인할 수 있음. 
setSingleChoiceItems(items: ArrayOf<SCharSequence!>!, checkItem: Int, listener: DialogInterface.OnClickListener): AlerDialog.Builder!): AlerDialog.Builder!

실제로 코드로 구현할땐 setText() 부분이 없어야 한다. 선택지와 중복이 되기 때문이다.

        val items = arrayOf("사과", "바나나", "토마토")
        button2.setOnClickListener {
            AlertDialog.Builder(this).run {
                setIcon(android.R.drawable.ic_dialog_info)
                setTitle("Hello")
                setItems(items, object: DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface?, which: Int) {
                        Log.d("Info", "선택 : ${items[which]}")
                    }
                })
                setPositiveButton("Yes", null)
                show()
            }
        }

setMultiChoiceItems() 함수는 초기에 설정하면서 checkItems 파라미터에서 확인 표시된 채로 나타날 항목을 선정할 수 있다.

        val items = arrayOf("사과", "바나나", "토마토")
        button2.setOnClickListener {
            AlertDialog.Builder(this).run {
                setIcon(android.R.drawable.ic_dialog_info)
                setTitle("Hello")
                setMultiChoiceItems(items, booleanArrayOf(true, false, false), object: DialogInterface.OnMultiChoiceClickListener {
                    override fun onClick(dialog: DialogInterface?, which: Int, isChecked: Boolean) {
                        Log.d("Info", "${items[which]} 이 ${if (isChecked) "선택되었습니다." else "선택 해제되었습니다."}")
                    }
                })
                setPositiveButton("Yes", null)
                show()
            }
        }

setSingleChoiceItems() 함수를 이용할 때 들어가는 숫자 역시 어느 인덱스에 있는 선택지가 선택된 채로 나올 것인지를 의미한다.

        val items = arrayOf("사과", "바나나", "토마토")
        button2.setOnClickListener {
            AlertDialog.Builder(this).run {
                setIcon(android.R.drawable.ic_dialog_info)
                setTitle("Hello")
                setSingleChoiceItems(items, 0, object: DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface?, which: Int) {
                        Log.d("Info", "${items[which]} 가 선택되었습니다.")
                    }
                } )
                setPositiveButton("Yes", null)
                show()
            }
        }

알림창 닫기 설정

  • setCancelable(Boolean): 뒤로가기 버튼을 눌렀을때 다이얼로그가 닫힐것인지
  • SetCanceledOnTouchOutside(Boolean): 다이얼로그 영역 바깥을 클릭했을때 다이얼로그가 닫힐 것인지

setCancelable() 함수는 AlertDialog.Builder 내부에 정의된 함수이고, SetCanceledOnTouchOutside() 는 외부에 정의된 함수이므로 각각 사용되는 위치가 다르다.

커스텀 다이얼로그 만들기

커스텀 다이얼로그 역시 AlertDialog 를 이용한다. 커스텀 다이얼로그를 만들기 위해서는 우선 LayoutInflater 클래스를 이해해야한다.

LayoutInflater

LayoutInflater 클래스는 레이아웃 XML 파일을 코드에서 초기화하는 기능을 제공한다. 우리가 viewBinding 을 쓸때 해당 클래스를 사용하였다.

 val binding = ActivityMainBinding.inflate(layoutInflater)

여기서 초기화란 XML 파일에 선언한 뷰를 코드에서 이용하고자 생성하는 작업을 의미한다. XML 파일은 텍스트 파일이기 때문에 코드에서 사용하기 위해서는 XML 에 선언한 대로 객체를 생성해서 메모리에 할당해야 한다. 이 작업을 LayoutInflater 클래스가 해준다. xml 파일과 액티비티를 바인딩하는 역할을 해주는거라고 이해된다.

그럼 setContentView() 는?

"setContentView() 는 인자로 받은 xml 레이아웃 리소스 id 에 해당하는 파일을 파싱하여 View 를 생성하고 View 의 속성을 지정하고 View 간의 위계질서에 맞춰 배치를 하는 역할을 한다. 이러한 일련의 과정을 전개(Inflate)라고 하며, 내부적으로 LayoutInflater 클래스를 참조한다."(출처)

setContentView() 는 액티비티에 있는 함수로서, 액티비티가 화면을 구성하는 것을 쉽게 하도록 도와주는 함수라고 생각하면 된다. 하지만 그 함수가 참조하는 LayoutInflater는 말그래도 XML 을 VIEW 로 바꿔주는 역할을 하기 때문에 액티비티 화면을 목적으로 만들어지지 않은 레이아웃 XML 을 활용할때 쓰인다.

LayoutInflater 활용

이를 이용해서 XML 파일을 초기화하는 작업은 어렵지 않다.
getSystemService() 를 이용해서 LayoutInflater 를 호출하고, inflate() 함수를 호출하면서 초기화할 레이아웃 XML 파일 정보를 매개변수로 전달한다.

        val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val rootView = inflater.inflate(R.layout.activity_some, null)

inflate() 함수의 반환값은 초기화된 XML의 루트 태그에 해당하는 객체이다. 만약 XML 파일의 루트 태그가 LinearLayout 이라면 LinearLayout 객체를 반환한다.

만약 뷰 바인딩을 사용중이라면 더 쉽게 만들 수 있다.

val binding = ActivityMainBinding.inflate(layoutInflater)
val rootView = binding.root

커스텀 다이얼로그 만들기

읽고있는 책이 1년 이상 된 책이기 때문에 안드로이드 문서를 따로 참고했다 참고한 문서
우선 XML 파일을 만들어서 커스텀 다이얼로그의 레이아웃을 구성해야한다.

<?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:orientation="vertical">
    
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
        
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="male"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="female"/>
    </RadioGroup>
</LinearLayout>
profile
개발자

0개의 댓글