스피너를 누르게 되면 네비게이션바가 올라오게 됩니다.
(위 상황은 조금 극단적일 수도 있지만..ㅎㅎ)
스피너 동작 시 네비게이션바가 올라오지 않게 하기 위해 어떻게 처리해야 되는지 정리하려고 합니다.
1. 스피너 네비게이션 바 숨기는 방법 -(1)
스피너 drop down 시 출력되는 팝업 창의 focusable 의 속성 값을 false 로 설정하는 메서드입니다.
object ViewUtil {
.....
fun avoidSpinnerDropdownFocus(spinner: AppCompatSpinner) {
try {
val listPopupField = AppCompatSpinner::class.java.getDeclaredField("mPopup")
listPopupField.isAccessible = true
val listPopup = listPopupField[spinner]
if (listPopup is androidx.appcompat.widget.ListPopupWindow) {
val popupField = androidx.appcompat.widget.ListPopupWindow::class.java.getDeclaredField("mPopup")
popupField.isAccessible = true
val popup = popupField[listPopup]
if (popup is PopupWindow) {
popup.isFocusable = false
}
}
} catch (e: NoSuchFieldException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
해당 메서드에 적용하고 싶은 스피너를 인자 값으로 넣고 아래와 같이 호출 해주시면
더 이상 스피너 클릭 시 네비게이션바가 올라오지 않습니다.
ViewUtil.avoidSpinnerDropdownFocus(binding.appCompatSpinner/*적용하고 싶은 Spinner*/)
여기서 하나 짚고 넘어가야 하는 게 있는데요,
스피너 위젯으로 AppComaptSpinner 를 사용하였습니다.
Spinner 로 사용하였을 때는 네비게이션바가 그대로 올라오더라구요...ㅠㅠ
해당 이유는 찾지 못 했지만 AppCompatSpinner 를 사용해도 문제는 없을 것 같습니다.
(혹시 알고 계신분이 있다면 댓글로 공유해주시면 감사하겠습니다..!)
<!-- <Spinner 는 왜 안되는거지.. -->
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/appCompatSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
2. 스피너 네비게이션 바 숨기는 방법 -(2)
만약 스피너를 꽤 많이 사용해야되는 상황이면
스피너를 정의할 때 마다 "avoidSpinnerDropdownFocus" 메서드를 호출해줘야 할 수도 있습니다.
이럴 때는 사용자 정의 Spinner 를 만드는 것도 좋은 방법이 될 것 같습니다
class HideNaviSpinner : AppCompatSpinner {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var mListener: OnSpinnerEventsListener? = null
private var mOpenInitiated = false
interface OnSpinnerEventsListener {
fun onSpinnerOpened(spinner: Spinner)
fun onSpinnerClosed(spinner: Spinner)
}
init {
// 스피너 네비게이션바 숨기기
avoidSpinnerDropdownFocus(this)
}
override fun performClick(): Boolean {
mOpenInitiated = true
isSelected = true
mListener?.apply { onSpinnerOpened(this@HideNaviSpinner) }
return super.performClick()
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
if (hasBeenOpened() && hasFocus) {
performClosedEvent()
}
}
fun setSpinnerEventsListener(onSpinnerEventsListener: OnSpinnerEventsListener) {
mListener = onSpinnerEventsListener
}
private fun performClosedEvent() {
mOpenInitiated = false
isSelected = false
mListener?.apply { onSpinnerClosed(this@HideNaviSpinner) }
}
private fun hasBeenOpened(): Boolean {
return mOpenInitiated
}
private fun avoidSpinnerDropdownFocus(spinner: AppCompatSpinner) {
try {
val listPopupField = AppCompatSpinner::class.java.getDeclaredField("mPopup")
listPopupField.isAccessible = true
val listPopup = listPopupField[spinner]
if (listPopup is androidx.appcompat.widget.ListPopupWindow) {
val popupField = androidx.appcompat.widget.ListPopupWindow::class.java.getDeclaredField("mPopup")
popupField.isAccessible = true
val popup = popupField[listPopup]
if (popup is PopupWindow) {
popup.isFocusable = false
}
}
} catch (e: NoSuchFieldException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
<com.example.hidenavibarspinner.HideNaviSpinner
android:id="@+id/appCompatSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
[Reference]
0 comments: