봄날은 갔다. 이제 그 정신으로 공부하자

PopupWindow로 Spinner 대체하기 본문

android Tip

PopupWindow로 Spinner 대체하기

길재의 그 정신으로 공부하자 2021. 1. 18. 11:01

개발 중 조금 난해한 문제가 발생했습니다.

요구사항을 파악해보면 Spinner로 개발하는게 맞는데 Spinner로 개발하기에는 너무 많은 리소스가 소모된다는 문제가 발생했습니다.

그래서 이걸 어떻게할까 고민하다 우선  Adapter도 만들고 layout xml도 만들고해서 Spinner로 만들어보았습니다. 

역시 만족스럽지 못했습니다. ㅠ_ㅠ

 

그래서 다른 개발자들이 만들어놓은 custom spinner를 찾아봤는데 미천한 검색 실력으로는 요구사항에 맞는 custom spinner를 찾을 수 없었습니다.

 

음… 어떡하지? 

 

그냥 쿨하게 Button에 PopupWindow를 사용해서 개발하기로 했습니다.

 

요구사항 자체가 Spinner에 비교했을 때 난해한 문제였지 PopupWindow를 사용해 개발하면 그리 어려운 개발 이슈가 아니었기에 

뚝딱 뚝딱 금방 개발을 할 수 있었습니다.


이렇게 이야기하고 조금 불안한 부분은 저는 원래 가급적이면 요구사항에 맞는 Control로 개발하는 것을 우선 시 합니다.

아무래도 위 언급한 것처럼 우회해서 개발하다보면 다른 예기치 못하는 문제가 발생하더라구요. ㅠ_ㅠ

 

각설하고 이 글에서는 해당 내용을 바탕으로 PopupWindow 사용하는 방법에 대해 설명합니다.

 

 

Spinner 짭 Button 만들기

Spinner 처럼 보여질 짭 버튼을 아래 이미지와 같이 만들어줍니다.

<androidx.appcompat.widget.AppCompatButton
    android:id="@+id/customSpinner
    android:layout_width="0dp"
    android:layout_height="60dp"
    android:layout_gravity="center"
    android:layout_marginStart="10dp"
    android:layout_marginEnd="10dp"
    android:background="@drawable/n_bg_round_white"
    android:drawableRight="@drawable/ic_bottom_array_grape"
    android:gravity="center"
    android:onClick="@{vmSelectType::onClickType}"
    android:paddingLeft="10dp"
    android:paddingRight="20dp"
    android:text="@string/type_all"
    android:textColor="@color/colorGrape"
    android:textSize="@dimen/dp18"
    android:textStyle="bold"
    android:stateListAnimator="@null"
    …/>

 

우측에 보여지는 화살표 이미지를 drawableRight를 사용해서 처리합니다.

이부분은 나중에 팝업이 보여지고 닫힐 때 이미지가 변경되도록 code에서 처리합니다.

팝업이 보여질 때 화살표를 변경해주고

(view as AppCompatButton).setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_up_arrow_grape, 0)

반대로 팝업이 닫힐 때도 화살표를 변경해줍니다.

(view as AppCompatButton).setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_bottom_array_grape, 0)

 

PopupWindow layout xml 만들기

리스트로 만들어도 되는데 여기는 예제니까, 그냥 TextView를 사용해서 만들도록 하겠습니다.

그냥 편하게 LinearLayout를 사용해서 TextView 3개를 사용했습니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="420dp"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/bg_round_grayline_unselected">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvAll"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:text="@string/type_all"
        android:textColor="@color/colorGrape"
        android:textSize="@dimen/dp20"
        android:textStyle="bold"/>
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvType1
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:text="@string/type1”
        android:textColor="@color/colorGrape"
        android:textSize="@dimen/dp20"
        android:textStyle="bold"/>
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvType2”
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:text="@string/type2”
        android:textColor="@color/colorGrape"
        android:textSize="@dimen/dp20"
        android:textStyle="bold"/>
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvType3”
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:paddingStart="20dp"
        android:paddingEnd="20dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:text="@string/type3
        android:textColor="@color/colorGrape"
        android:textSize="@dimen/dp20"
        android:textStyle="bold"/>
</LinearLayout>

 

PopupWindow 처리하기

이제 사용자가 버튼을 눌렀을 때 팝업이 보여주는 처리를 해줍니다.

처리는 SelectTypeViewModel의 onClickType()함수에서 처리해줍니다.

 

팝업 윈도우는 특정 View에 종속되어 보여지기 때문에 Dialog와 달리 정중앙이 아닌 부모 View의 하단에 보여집니다.

아래 코드의 view는 위 생성한 Button의 View 입니다.

 

자세한 설명은 아래 코드에 주석으로 추가하였습니다.

// 위에서 만들어놓은 popup_type layout xml를 불러옵니다.
val inflater = view.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val popupView = inflater.inflate(R.layout.popup_type, null)

// 위에서 불러온 popupView를 가진 PopupWindow를 생성해줍니다.
val popupWindow = PopupWindow(popupView, view.width, ViewGroup.LayoutParams.WRAP_CONTENT)
popupWindow.isOutsideTouchable = true // 팝업 윈도우 바깥 영역 터치 허용
popupWindow.isFocusable = true // 포커스를 가질 수 있도록 허용 
popupWindow.showAsDropDown(view)  // DropDown 타입으로 팝업 생성
// 팝업이 종료 될 때 호출되는 함수 오버라이드 및 처리
popupWindow.setOnDismissListener{
    closePopup(view)
}
// 팝업 아이템 클릭 처리
popupView.tvAll.setOnClickListener {
    // code
}
popupView.tvType1.setOnClickListener {
    // code
}
popupView.tvType2.setOnClickListener {
    // code
}
popupView.tvType3.setOnClickListener {
    // code
}

 

이게 입니다. 별거 없습니다. ^___^;;;

Comments