전체 화면(full screen)을 사용하고 있는 앱이라도 스피너를 누르게 되면 네비게이션바가 올라오게 됩니다. (위 상황은 조금 극단적일 수도 있지만..ㅎㅎ) 스피너 동작 시 네비게이션바가 올라오지 않게 하기 위해 어떻게 처리해야 되는지 정리하려고...

[안드로이드] 스피너 네비게이션바 숨기기


 전체 화면(full screen)을 사용하고 있는 앱이라도

스피너를 누르게 되면 네비게이션바가 올라오게 됩니다.

(위 상황은 조금 극단적일 수도 있지만..ㅎㅎ)

스피너 동작 시 네비게이션바가 올라오지 않게 하기 위해 어떻게 처리해야 되는지 정리하려고 합니다.



 

 

 

 

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]

Stackoverflow

 




0 comments: