Vintage appMaker의 Tech Blog

[Android] PopupWindow 사용 - closure 예제 본문

Source code or Tip/Android(Java, Kotlin)

[Android] PopupWindow 사용 - closure 예제

VintageappMaker 2021. 5. 30. 15:25

Android에서 어떤 위젯 근처의 특정 크기와 위치로 새로운 위젯을 보여주고 싶다면 PopupWindow를 생성하고 showAsDropDown()으로 특정 위젯기준으로 위치와 크기를 지정하여 화면에 보여줄 수 있다. 

 

 

PopupWindow  |  Android 개발자  |  Android Developers

 

developer.android.com

 

그러나 화면에 PopupWindow를 자주 사용해야 할 경우, PopupWindow 객체를 보관 후, dismiss()를 호출하는 것이 귀찮을 때다 많다. 그럴 경우, kotlin에서는 확장함수와 closure를 이용해 범용적으로 편하게(???) 사용할 수 있다. 

 

📢 [PopupWindow 관리용 확장함수]

fun View.dpToPx(dp: Float): Int = context.dpToPx(dp)
fun Context.dpToPx(dp: Float): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()

// pop을 관리하기 싫어서 closure로 생성함
data class PopupInfo(
        val v : View,
        val width  : Int,
        val height : Int,
        val x  : Int,
        val y : Int
)

// makePopupClosure를 한 번에 실행
fun Context.quickPopup(toView: View, fnSetup : (()->Unit ) -> PopupInfo){
    fun makePopupClosure(toView: View, fnSetup : (()->Unit ) -> PopupInfo) : ()->Unit{
        var pop : PopupWindow? = null
        fun dismiss() = pop?.dismiss()
        return {

            val popInfo = fnSetup(::dismiss)

            val width  = if(popInfo.width == 0 ){
                ViewGroup.LayoutParams.WRAP_CONTENT
            } else dpToPx(popInfo.width.toFloat())

            val height = if(popInfo.height == 0 ){
                ViewGroup.LayoutParams.WRAP_CONTENT
            } else dpToPx(popInfo.height.toFloat())

            pop = PopupWindow(
                popInfo.v,
                width,
                height,
                true
            ).apply {
                showAsDropDown(toView, popInfo.x, popInfo.y)
            }
        }
    }

    makePopupClosure(toView){
            dismiss ->
        fnSetup(dismiss)
    }.apply { this() }
}

📢 사용예 

    val button = findViewById<Button>(R.id.button)
    button.setOnClickListener {
        quickPopup(button){
            fnDismiss ->
            val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            val view = inflater.inflate(R.layout.popup_item, null)

            view.findViewById<TextView>(R.id.text_menu1)?.apply{
                setOnClickListener {
                    Toast.makeText(this@PopUpTestActivity, "click", Toast.LENGTH_LONG).show()
                    fnDismiss()
                }
            }

            // width, height가 0이면 wrap_contents
            return@quickPopup PopupInfo(view, 0, 40, 30, 0)
        }
    }
Comments