본문 바로가기
Kotlin

[Kotlin / Android] 10. 다이얼로그와 알림 이용하기 - 다양한 다이얼로그

by 쀼르쀼르 2024. 3. 19.

10-3 다양한 다이얼로그


 

 

다이얼로그(dialog)

- 사용자와 상호 작용하는 대화상자

 

토스트 메시지 띄우기

토스트(Toast)

- 화면 아래쪽에 잠깐 보였다가 사라지는 문자열을 의미

- 사용자에게 간단한 메시지로 특정한 상황을 알릴 때 사용함

 

토스트를 사용하는 대표적인 예로

 

사용자가 폰의 뒤로가기 버튼을 눌러 앱이 종료될 때

"종료하려면 한 번 더 누르세요."를 띄울 수 있음

 

이 밖에

간단한 예외 메시지를 출력할 때도 많이 사용함

 

토스트는 ToastmakeText( ) 함수로 만듦

  • open static fun makeText(context: Context!, text:
    CharSequence!, duration: Int): Toast!
  • open static fun makeText(context: Context!, resId:
    Int, duration: Int): Toast!

 

makeText( ) 함수의

두 번째 매개변수출력할 문자열

 

세 번째 매개변수토스트가 화면에 출력되는 시간으로

보통 다음의 상수를 사용함

  • val LENGTH_LONG: Int
  • val LENGTH_SHORT: Int

Toast.LENGTH_SHORT일반적으로 3초 정도

 

Toast.LENGTH_LONG5초 정도의 시간을 의미

 

토스트가 화면에 출력된 후 이 시간이 지나면 자동으로 사라짐

 

· 토스트 출력 예

val toast = Toast.makeText(this, "종료하려면 한 번 더 누르세요", Toast.LENGTH_SHORT)
toast.show()

 

makeText( ) 함수로 만든 토스트는 show( ) 함수로 화면에 출력함

세터 함수로도 만들 수 있음

  • open fun setDuration(duration: Int): Unit
  • open fun setGravity(gravity: Int, xOffset: Int, yOffset: Int): Unit
  • open fun setMargin(horizontalMargin: Float, verticalMargin: Float): Unit
  • open fun setText(resId: Int): Unit

setDuration( ), setText( ) 함수 이용하면

문자열이나 화면에 보이는 시간을 설정할 수 있음

 

setGravity( )setMargin( ) 함수 이용하면

토스트가 뜨는 위치를 정할 수도 있음

 

토스트가 화면에 보이거나 사라지는 순간을

콜백으로 감지해 특정 로직을 수행하게 할 수도 있음

(API 레벨 30 버전에서 추가됨)

콜백 기능 이용한다면 API레벨 호환성 고려해 작성해야 함

 

· 콜백 기능 이용하기

@RequireApi(Build.VERSION_CODES.R)   API 레벨 호환성 애너테이션
fun showToast() {
    val toast = Toast.makeText(this, "종료하려면 한 번 더 누르세요.", Toast.LENGTH_SHORT)
    toast.addCallback(
        object: Toast.Callback() {
            override fun onToastHidden() {
                super.onToastHidden()
                Log.d("kkang", "toast hidden")
            }
            
            override fun onToastShown() {
                super.onToastShown()
                Log.d("kkang", "toast shown")
            }
        })
    toast.show()
}

 

토스트의 콜백 등록하려면 Toast.Callback 타입의 객체를

토스트 객체의 addCallback( ) 함수로 등록해 주면 됨

 

이렇게 하면 화면에 토스트가 뜨는 순간

자동으로 콜백 객체의 onToastShown( ) 함수가 호출되며

화면에서 사라지는 순간 onToastHidden( ) 함수가 자동으로 호출됨

 


 

 

날짜 또는 시간 입력받기

 

피커(Picker) 다이얼로그

- 사용자에게 날짜나 시간을 입력받는 데 사용하는 다이얼로그

 

데이트 피커 다이얼로그(DatePickerDialog)

- 날짜를 입력받을 때 사용

 

타임 피커 다이얼로그(TimePickerDialog)

- 시간을 입력받을 때 사용

 

· 데이트 피커 다이얼로그 생성자

DatePickerDialog(context: Context, listener: DatePickerDialog.OnDateSetListener?,
year: Int, month: Int, dayOfMonth: Int)

 

두 번째 매개변수

DatePickerDialog.OnDateSetListener 구현 객체를 등록하면

다이얼로그에서 사용자가 설정한 날짜를 콜백 함수로 얻을 수 있음

 

Int 타입의 매개변수

처음에 보이는 날짜임. month값은 0부터 11까지 지정되며 이때 0은 1월을 의미

 

· 데이트 피커 다이얼로그 사용 예

DatePickerDialog(this, object: DatePickerDialog.OnDateSetLitener {
    override fun onDateSet(p0: DatePicker?, p1: Int, p2: Int, p3: Int) {
        Log.d("kkang", "year: $p1, month: ${p2+1}, dayOfMonth : $p3")
    }
}, 2022, 4, 6).show()

 

 실행 결과 

 

· 타임 피커 다이얼로그 생성자

TimePickerDialog(context: Context!, listener: TimePickerDialog.OnTimeSetListener!,
hourOfDay: Int, minute: Int, is24HourView: Boolean)

 

두 번째 매개변수

TimePickerDialog.OnTimeSetListener를 구현한 객체를 지정하면

사용자가 다이얼로그에서 설정한 시간을 얻을 수 있으며

처음에 보일 시간을 Int 타입으로 설정할 수 있음

 

마지막 매개변수

시간을 24시간과 12시간 형태 중에 어떤 것으로 출력할 것인지를 지정함

 

false로 지정해 12시간 형태로 출력하면

오전 / 오후를 선택하는 부분이 보임

 

ture로 지정해 24시간 형태로 출력하면

오전 / 오후를 선택하는 부분이 보이지 않음

 

· 타임 피커 다이얼로그 사용 예

TimePickerDialog(this, object: TimePickerDialog.OnTimeSetListener {
    override fun onTimeSet(p0: TimePicker?, p1: Int, p2: Int) {
        Log.d("kkang", "time : $p1, minute : $p2")
    }
}, 15, 0, true).show()

 

 

 실행 결과 

 


 

 

알림 창 띄우기

 

안드로이드 다이얼로그의 기본은 알림 창으로 부르는 AlertDialog

알림 창은 단순히 메시지만 출력할 수도 있고 다양한 화면을 출력할 수도 있음

 

데이트 피커와 타임 피커도 AlertDialog의 하위 클래스이며

각각의 화면에 데이트 피커와 타임 피커를 출력한 다이얼로그임

 

알림 창은 크게 3가지 영역으로 구분됨

위부터 차례대로 제목, 내용, 버튼 영역이 있음

 

알림 창의 영역

 

알림 창을 설정할 때 제목과 버튼 정보를 지정하지 않았다면 내용 영역만 나옴

 

내용 영역만 출력된 알림 창

 

알림 창의 생성자는 접근 제한자가 protected로 선언돼서 객체를 직접 생성할 수 없음

 

그 대신 AlertDialog.Builder를 제공하므로 이 빌더를 이용해 알림 창을 만듦

먼저 AlertDialog.Builder를 생성하고 빌더의 세터 함수로 알림 창 정보를 지정함

 

· 알림 창 빌더

AlertDialog.Builder(context: Context!)

 

다음은 알림 창에 아이콘과 제목, 내용을 지정하는 함수임

  • open fun setIcon(iconId: Int): AlertDialog.Builder!
  • open fun setTitle(title: CharSequence!): AlertDialog.Builder!
  • open fun setMessage(message: CharSequence!): AlertDialog.Builder!

 

setIcon( ) 함수는 제목 영역에 아이콘을 출력함

 

setTitle( ) 함수는 제목 문자열을 출력함

 

setMessage( ) 함수는 내용 영역에 간단한 문자열을 출력함

 

 

다음은 알림 창에 버튼을 지정하는 함수임

  • open fun setPositiveButton(text: CharSequence!, listener: DialogInterface.OnClick
    Listener!): AlertDialog.Builder!
  • open fun setNegativeButton(text: CharSequence!, listener: DialogInterface.OnClick
    Listener!): AlertDialog.Builder!
  • open fun setNeutralButton(text: CharSequence!, listener: DialogInterface.OnClick
    Listener!): AlertDialog.Builder!

 

각 함수의

첫 번째 매개변수버튼의 문자열

 

두 번째 매개변수사용자가 버튼 클릭했을 때 처리할 이벤트 핸들러

만약 버튼 클릭했을 때 처리할 내용이 없다면 두 번째 매개변수에 null을 대입함

 

알림 창의 버튼은 최대 3개까지만 추가할 수 있음

같은 함수 여러 번 사용하면 버튼 중복되어 하나만 나타남

 

· 알림 창 띄우기

AlertDialog.Builder(this).run {
    setTitle("test dialog")
    setIcon(android.R.drawable.ic_dialog_info)
    setMessage("정말 종료하시겠습니까?")
    setPositiveButton("OK", null)
    setNegativeButton("Cancel", null)
    setNeutralButton("More", null)
    setPositiveButton("Yes", null)
    setNegativeButton("No", null)
    show()
}

 

 실행 결과 

 

버튼 함수를 setPositiveButton( ), setNegativeButton( ),

setNeutralButton( ) 으로 구분하는 이유

→ 이벤트 핸들러에서 어떤 버튼이 클릭되었는지 구분하기 위해서

 

각 이벤트에 해당하는 이벤트 핸들러 따로 만들 수도 있지만,

한 알림 창의 버튼 이벤트를 하나의 이벤트 핸들러에서 모두 처리할 수도 있음

 

이때 어떤 버튼이 클릭되었는지를 구분해야 함

셋 중 어떤 함수를 사용했는지에 따라

이벤트 핸들러에 전달되는 매개변숫값이 달라서 그 값으로 구분함

 

· 버튼의 이벤트 핸들러 등록

val eventHandler = object : DialogInterface.OnClickListener {
    override fun onClick(p0: DialogInterface?, p1: Int) {
        if (p1 == DialogInterface.BUTTON_POSITIVE) {
            Log.d("kkang", "positive button click")
        } else if (p1 == DialogInterface.BUTTON_NEGATIVE) {
            Log.d("kkang", "negative button click")
        }
    }
}
(...생략...)
setPositiveButton("OK", eventHandler)
setNegativeButton("Cancel", eventHandler)

 

 

알림 창 클릭했을 때 호출되는 onClick( ) 함수의

두 번째 매개변수이벤트가 발생한 버튼을 알려줌

 

setPositiveButton( ) 함수로 만든 버튼은

이벤트 구분자가 DialogInterface.BUTTON_POSITIVE로 지정되며,

 

setNegativeButton( ) 함수로 만든 버튼은

이벤트 구분자가 DialogInterface.BUTTON_NEGATIVE로 지정됨

 

 

목록을 제공하고 이 중 하나를 선택받는 알림 창을 만들고자 한다면

setItems( ), setMultiChoiceItems( ), setSingleChoiceItems( ) 함수를 이용함

 

함수에서 첫 번째 매개변수배열 정보이며 이곳의 문자열이 목록에 출력됨

  • open fun setItems(items: Array<CharSequence!>!, listener: DialogInterface.On
    ClickListener!): AlertDialog.Builder!
  • open fun setMultiChoiceItems(items: Array<CharSequence!>!, checkedItems: BooleanArray!,
    listener: DialogInterface.OnMultiChoiceClickListener!): AlertDialog.Builder!
  • open fun setSingleChoiceItems(items: Array<CharSequence!>!, checkedItem: Int, listener:
    DialogInterface.OnClickListener!): AlertDialog.Builder!

 

· 목록을 출력하는 알림 창

val items = arrayOf<String>("사과", "복숭아", "수박", "딸기")
AlertDialog.Builder(this).run{
    setTitle("items test")
    setIcon(android.R.drawable.ic_dialog_info)
    setItems(items, object: DialogInterface.OnClickListener {
        override fun onClick(p0: DialogInterface?, p1: Int) {
            Log.d("kkang", "선택한 과일 : ${items[p1]}")
        }
    })
    setPositiveButton("닫기", null)
    show()
}

 

 실행 결과 

 

setItems( ) 함수의

두 번째 매개변수항목을 선택할 때의 이벤트 핸들러이며

사용자가 항목 선택하면 onClick( ) 함수가 자동으로 호출됨

 

사용자가 선택한 항목의 인덱스는

onClick( ) 함수의 두 번째 매개변수로 전달됨


 

setMultiChoiceItems( ) 함수는

다중 선택을 위한 체크박스가 함께 출력되는 항목을 만들어 줌

두 번째 매개변수처음 체크 상태를 지정

 

· 체크박스를 포함하는 예

setMultiChoiceItems(items, booleanArrayOf(true, false, true, false), object: Di-
alogInterface.OnMultiChoiceClickListener {
    override fun onClick(p0: DialogInterface?, p1: Int, p2: Boolean) {
        Log.d("kkang", "${items[p1]} 이 ${if(p2) "선택되었습니다." else "선택 해제되었습니다."}")
    }
})

 

 실행 결과 

 

setMultiChoiceItems( ) 함수의

세 번째 매개변수항목을 선택할 때의 이벤트 핸들러이며

사용자가 항목을 선택하는 순간 onClick( ) 함수가 자동으로 호출됨

 

onClick( ) 함수의

두 번째 매개변수로 선택한 항목의 인덱스가 전달되며

세 번째 매개변수체크 상태가 전달

 


 

setSingleChoiceItems( ) 함수는

하나만 선택할 수 있는 라디오 버튼으로 구성된 항목을 만들어 줌

두 번째 매개변수로 처음 선택할 항목을 지정

 

· 라디오 버튼을 포함하는 예

setSingleChoiceItems(items, 1, object: DialogInterface.OnClickListener {
    override fun onClick(p0: DialogInterface?, p1: Int) {
        Log.d("kkang", "${items[p1]} 이 선택되었습니다.")
    }
})

 

 실행 결과 

 

알림 창의 제목, 내용, 버튼을 구성하는 함수 이외에

속성을 설정하는 함수를 사용할 수도 있음

  • open fun setCancelable(cancelable: Boolean): AlertDialog.Builder!
  • open fun setCanceledOnTouchOutside(cancel: Boolean): Unit

 

두 함수 모두 사용자의 행동에 따라 알림 창을 닫을 것인지를 설정함

 

setCancelable( ) 함수는

사용자가 기기의 뒤로가기 버튼을 눌렀을 때

 

setCanceledOnTouchOutside( ) 함수는

알림 창의 바깥 영역을 터치했을 때

매개변수가 true이면 닫고 false이면 닫지 않음. 기본값은 true

 

· 알림 창을 닫는 설정(뒤로가기, 바깥 영역 터치)

AlertDialog.Builder(this).run {
    setTitle("items test")
    setIcon(android.R.drawable.ic_dialog_info)
    setItems(items, object: DialogInterface.OnClickListener {
        override fun onClick(p0: DialogInterface?, p1: Int) {
            Log.d("kkang", "선택한 과일 : ${items[p1]}")
        }
    })
    setCancelable(false)
    setPositiveButton("닫기", null)
    show()
}.setCanceledOnTouchOutside(false)

 


 

커스텀 다이얼로그 만들기

 

커스텀 다이얼로그도 AlertDialog를 이용함

 

LayoutInflater 클래스는레이아웃 XML 파일을 코드에서 초기화

(흔히 전개라고도 표현)하는 기능을 제공함

 

초기화란 XML 파일에 선언한 뷰를 코드에서 이용하고자 생성하는 작업을 의미

 

XML 파일은 텍스트 파일일 뿐 결국 코드에서 이용하려면XML에 선언한 대로

객체를 생성해서 메모리에 할당해야 함이 작업을 LayoutInflater가 해줌

 

XML 파일 초기화

 

LayoutInflater로 레이아웃 XML 파일 초기화 하는 작업

  1. getSystemService( ) 함수로 LayoutInflater를 얻음
  2. inflate( ) 함수를 호출하면서 초기화할 레이아웃 XML 파일 정보를 매개변수로 전달함

 

· XML 파일 초기화

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

 

inflate( ) 함수의 반환값은 초기화된 XML의 루트 태그에 해당하는 객체

만약 XML 파일의 루트 태그가 <LinearLayout>이면 LinearLayout 객체를 반환함

 

뷰 바인딩으로 작성해도 됨

 

· 뷰 바인딩을 적용한 XML 파일 초기화

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

 

초기화할 XML에 해당하는 바인딩 클래스의 inflate( ) 함수를 호출하면서

매개변수로 layoutInflater 객체를 전달만 해주면 자동으로 초기화되고

루트 뷰 객체를 얻을 수 있음

 

커스텀 다이얼로그 만드는 방법

  1. 다이얼로그 구성하는 레이아웃 XML 파일 만들기 (res/layout 폴더)
  2. XML 파일 LayoutInflater로 초기화해서 다이얼로그에 적용하기
  3. AlertDialogsetView( ) 함수에 매개변수로 뷰 객체 전달하면 창의 내용 영역에 출력됨

 

· 커스텀 다이얼로그 구성

<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>

 

· 커스텀 다이얼로그 출력

val dialogBinding = DialogInputBinding.inflate(layoutInflater)
AlertDialog.Builder(this).run {
    setTitle("Input")
    setView(dialogBinding.root)
    setPositiveButton("닫기", null)
    show()
}

 

 실행 결과