decor view์ ์ฐ์์ ๋ํด ์์๋ณด๋ค๊ฐ ์์คํ ๋ฐ ์ ์ด๋ฅผ ๋ณด๊ฒ ๋๋ค.
์์คํ ๋ฐ๋ ๋ฌด์์ ์๋ฏธํ๋
https://developer.android.com/training/system-ui
The system bars are screen areas dedicated to the display of notifications, communication of device status, and device navigation. Typically the system bars (which consist of the status and navigation bars, as shown in figure 1) are displayed concurrently with your app.
๋ฐ๋ฒ์ญ
์์คํ ๋ฐ๋ ์๋ฆผ ๋ ธ์ถ, ๋จ๋ง์ ํต์ ์ํ, ๋จ๋ง ํ์์ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์๋ ์คํฌ๋ฆฐ ์์ญ๋ค์ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์์คํ ๋ฐ๋ (์ํ๋ฐ, ๋ค๋น๊ฒ์ด์ ๋ฐ๋ฅผ ํฌํจํด์, ๊ทธ๋ฆผ 1์์ ๋ณด๋ฏ์ด) ์ฑ์ ๋์์ ๋ ธ์ถ๋ฉ๋๋ค.
๊ณต์๋ฌธ์์์ ์ ์ํด์ค. ์ผ๋ฐ์ ์ผ๋ก
์์คํ ๋ฐ = ์ํ ๋ฐ + ๋ค๋น๊ฒ์ด์ ๋ฐ
์ด๋ฆฌ ์ ๋ฆฌ ์ฝ๋๋ค์ ์ดํผ๋ค๊ฐ, WindowInsetCompat.Type์ ์ ํ๋ค. WindowInsetsCompat.Type์์ systmeBars() ๋ผ๋ ๋ฉ์๋๊ฐ ์๋ค๋ ๊ฒ์ ํ์ธํ๋ค. ์ด๋ ๊ฒ API์์ ์์คํ ๋ฐ๋ผ๊ณ ์ ํด์ค ๊ฒ์ด ๋ฌด์์ธ์ง ํ์ธํด๋ณด์๋ค.
์ํ ๋ฐ์ ๋ค๋น๊ฒ์ด์ ๋ฐ๋ ๋น์ฐํ ์์ ๊ฒ์ ์์๋๋ฐ, ์บก์ ๋ฐ๋ผ๋ ๊ฒ๋ ์์คํ ๋ฐ์ ์ํ๋ค๋ ๊ฒ์ ์์๋ค. ๊ทธ๋์ ์บก์ ๋ฐ๊ฐ ๋ฌด์์ธ๋ฐ? ์๋ง์ด์๋ค.
์๋๋ก์ด๋ ์๋์ฐ ์ชฝ์์ ์ฝ๋ ์ ๊ตฌ๋ถ๋ ํ์ ์ผ๋ก
์์คํ ๋ฐ = ์ํ ๋ฐ + ๋ค๋น๊ฒ์ด์ ๋ฐ + ์๋ง ์์ญ
์์คํ ๋ฐ ํ๋ฆฌ๊ฒ ๋ง๋ค๊ธฐ
์์คํ ๋ฐ ํ๋ฆฌ๊ฒ ๋ง๋ค๊ธฐ - Android R(API Level 30) ๋ฏธ๋ง
https://developer.android.com/training/system-ui/dim
decorView์ setSystemUiVisibility()์ ๋งค๊ฐ๋ณ์๋ฅผ View.SYSTEM_UI_FLAG_LOW_PROFILE๋ก ๋ฃ์ด์ค๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
fun turnOnOffDimSystemBar() {
if (requireActivity().window.decorView.systemUiVisibility != View.SYSTEM_UI_FLAG_LOW_PROFILE) {
// dim ์ฒ๋ฆฌํ๊ธฐ
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LOW_PROFILE
} else {
// ์๋ ์ํ๋ก ๋ณต๊ตฌํ๊ธฐ
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_VISIBLE
// View.SYSTEM_UI_FLAG_VISIBLE = 0 ๊ฐ์
}
}
์์คํ ๋ฐ ํ๋ฆฌ๊ฒ ๋ง๋ค๊ธฐ - Android R ์ด์
View.SYSTEM_UI_FLAG_LOW_PROFILE์ View.setSystemUiVisibility()๊ฐ deprecated ๋๋ค.
Dim ์ฒ๋ฆฌ ํ ๋ฐ์ ์์ ์์คํ ๋ฐ๋ฅผ ์จ๊ฒจ๋ฒ๋ฆฌ๋ผ๊ณ ํ๋ค. ์ด๊ฑด ๋ฐ์์ ์ดํด๋ณธ๋ค.
์ํ ๋ฐ ์จ๊ธฐ๊ธฐ
์ํ ๋ฐ ์จ๊ธฐ๊ธฐ - Android 4.0 ์ดํ
Android 4.0์ 2011๋ ์ ๊ณต๊ฐ๋์๋ค๊ณ . ๊ตฌ์ง Android 4.0 ์ดํ ๋จ๋ง์ ๊ตฌํ์ ๊ณต๋ถํ ํ์๋ ์๋ค๋ ์๊ฐ์ด ๋ ๋ค. ์คํต.
์ํ ๋ฐ ์จ๊ธฐ๊ธฐ - Android 4.1 ์ด์ ~ Android R(11) ๋ฏธ๋ง
decorView์ setSystemUiVisibility()์ ๋งค๊ฐ๋ณ์๋ฅผ View.SYSTEM_UI_FLAG_FULLSCREEN์ผ๋ก ๋ฃ์ด์ค๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
fun hideOrShowStatusBar() {
if (requireActivity().window.decorView.systemUiVisibility != View.SYSTEM_UI_FLAG_FULLSCREEN) {
// ํน์
// if (requireActivity().window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) ์ฌ์ฉ
// ์จ๊ธฐ๊ธฐ
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_FULLSCREEN
// or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// ์ด ํ๋๊ทธ๋ฅผ ์ถ๊ฐํ๋ฉด ์ํ๋ฐ๊ฐ ์ฌ๋ผ์ง๋ ๊ฒ์ด ์์ฐ์ค๋ฌ์ ๋ค.
} else {
// ๋ณด์ด๊ฒ ํ๊ธฐ
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_VISIBLE
// View.SYSTEM_UI_FLAG_VISIBLE = 0 ๊ฐ์
}
}
์ํ ๋ฐ ์จ๊ธฐ๊ธฐ - Android R(11) ์ด์
WindowInsetsControllerCompat.hide()์ WindowInsetsCompat.Type.statusBars()๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฃ์ด์ ์ฐ๋ฉด ๋๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
fun hideOrShowStatusBarOverAndroidR() {
val windowInsetsController = WindowCompat.getInsetsController(
requireActivity().window,
requireActivity().window.decorView
)
requireActivity().window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
if (windowInsets.isVisible(WindowInsetsCompat.Type.statusBars())) {
windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
} else {
windowInsetsController.show(WindowInsetsCompat.Type.statusBars())
}
view.onApplyWindowInsets(windowInsets)
}
}
๋ค๋น๊ฒ์ด์ ๋ฐ ์จ๊ธฐ๊ธฐ
๋ค๋น๊ฒ์ด์ ๋ฐ ์จ๊ธฐ๊ธฐ - Android R(11) ๋ฏธ๋ง
๊ณต์ ๋ฌธ์๋ฅผ ๋ณด๋ ๋ค๋น๊ฒ์ด์ ๋ฐ ์จ๊ธฐ๊ธฐ ๊ธฐ๋ฅ์ Android 4.0, 4.1 ๋ ์ฆ์๋ถํฐ ๋ฑ์ฅํ ๋ฏ ํ๋ค. Andriod 4.0์ด ๋ฑ์ฅํ ์ง 10๋ ์ด ์ง๋ฌ์ผ๋, Android R ๋ฏธ๋ง์ ๊ตฌํ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ๋ง ์ฌ๊ฒจ๋ ๋ ๋ฏ ํ๋ค.
https://developer.android.com/training/system-ui/navigation
decorView์ setSystemUiVisibility()์ ๋งค๊ฐ๋ณ์๋ฅผ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION์ผ๋ก ๋ฃ์ด์ค๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์ ์์ฑํ๋ค.
fun hideOfShowNavigationBar() {
if (requireActivity().window.decorView.systemUiVisibility != View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) {
// ํน์
// if (requireActivity().window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
} else {
requireActivity().window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_VISIBLE
// View.SYSTEM_UI_FLAG_VISIBLE = 0 ๊ฐ์
}
}
๋ค๋น๊ฒ์ด์ ๋ฐ ์จ๊ธฐ๊ธฐ - Android R(11) ์ด์
https://developer.android.com/develop/ui/views/layout/immersive#type
WindowInsetsControllerCompat.hide()์ WindowInsetsCompat.Type.navigationBars()๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฃ์ด์ ์ฐ๋ฉด ๋๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์ ์์ฑํ๋ค.
fun hideOrShowNavigationBarOverAndroidR() {
val windowInsetsController = WindowCompat.getInsetsController(
requireActivity().window,
requireActivity().window.decorView
)
requireActivity().window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
if (windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars())) {
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
} else {
windowInsetsController.show(WindowInsetsCompat.Type.navigationBars())
}
view.onApplyWindowInsets(windowInsets)
}
}
์์คํ ๋ฐ ์จ๊ธฐ๊ธฐ. ์ ์ฒด ํ๋ฉด ๋ชจ๋
์์คํ ๋ฐ ์จ๊ธฐ๊ธฐ. ์ ์ฒด ํ๋ฉด ๋ชจ๋ - Android R ๋ฏธ๋ง
decorView์ setSystemUiVisibility()์ ๋งค๊ฐ๋ณ์์ ํ๋๊ทธ๋ค์ ์ค์ ํ๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
fun showOrHideSystemBar() {
if (requireActivity().window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
requireActivity().window.decorView.systemUiVisibility =
(View.SYSTEM_UI_FLAG_IMMERSIVE
// ์์คํ
๋ฐ๊ฐ ์ฌ๋ผ์ง๊ฑฐ๋ ๋ณด์ด๊ฑฐ๋ ํ ๋์ ์์คํ
๋ฐ ์๋์ ์ฝํ
์ธ ๊ฐ
// ๋ฆฌ์ฌ์ด์ง๋์ง ์๋๋ก ์ค์ ํ๋ค.
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// ๋ค๋น๊ฒ์ด์
๋ฐ์ ์ํ ๋ฐ๋ฅผ ์จ๊ธด๋ค.
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN)
} else {
// ์ฝํ
์ธ ์ y ์ขํ ๋ฐฉํฅ ์์ชฝ์ด ์๋๋ผ, z ์ขํ ๋ฐฉํฅ ์์ชฝ์ผ๋ก
// ์์คํ
๋ฐ๊ฐ ๋ํ๋๋ ๊ฒ์ ํ
์คํธ๋ก ํ์ธํ๋ค.
// ์์คํ
๋ฐ๊ฐ ์ฝํ
์ธ ๋ฅผ ๊ฐ๋ฆด ์ ์๋ค.
requireActivity().window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
)
}
}
์์คํ ๋ฐ ์จ๊ธฐ๊ธฐ. ์ ์ฒด ํ๋ฉด ๋ชจ๋ - Android R ์ด์
https://developer.android.com/develop/ui/views/layout/immersive#type
WindowInsetsControllerCompat.hide()์ WindowInsetsCompat.Type.systemBars()๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฃ์ด์ ์ฐ๋ฉด ๋๋ค.
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
fun hideOrShowSystemBarOverR() {
val windowInsetsController = WindowCompat.getInsetsController (
requireActivity().window,
requireActivity().window.decorView
)
requireActivity().window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
// ๋ค๋น๊ฒ์ด์
๋ฐ๋ ์ํ๋ฐ๊ฐ ๋
ธ์ถ๋์ด ์์ ๋
if (windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars())
|| windowInsets.isVisible(WindowInsetsCompat.Type.statusBars())
) {
// ๋ค๋น๊ฒ์ด์
๋ฐ๋ ์ํ๋ฐ ๋ฟ๋ง์ด ์๋๋ผ ์์คํ
๋ฐ๊น์ง๋ ์จ๊ธด๋ค.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
} else {
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
}
}
}
์์คํ ๋ฐ ๋ ธ์ถ ์ฌ๋ถ๋ฅผ ์ ์ ์๋ ๋ฆฌ์ค๋
์์คํ ๋ฐ ๋ ธ์ถ ์ฌ๋ถ๋ฅผ ์ ์ ์๋ ๋ฆฌ์ค๋ - Android R ๋ฏธ๋ง
https://developer.android.com/training/system-ui/visibility?hl=ko
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
requireActivity().window.decorView.setOnSystemUiVisibilityChangeListener {
if (it and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION == 0) {
// ๋ค๋น๊ฒ์ด์
๋ฐ ๋
ธ์ถ๋จ
} else {
// ๋ค๋น๊ฒ์ด์
๋ฐ ์จ๊ฒจ์ง
}
if (it and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
// ์ํ๋ฐ ๋
ธ์ถ๋จ
} else {
// ์ํ๋ฐ ์จ๊ฒจ์ง
}
if (it and View.SYSTEM_UI_FLAG_LOW_PROFILE == 0) {
// ์์คํ
๋ฐ ๋ค ์ฒ๋ฆฌ ์์
} else {
// ์์คํ
๋ฐ ๋ค ์ฒ๋ฆฌ๋จ
}
}
์์คํ ๋ฐ ๋ ธ์ถ ์ฌ๋ถ๋ฅผ ์ ์ ์๋ ๋ฆฌ์ค๋ - Android R ์ด์
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
val windowInsetsController = WindowCompat.getInsetsController(
requireActivity().window,
requireActivity().window.decorView
)
requireActivity().window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
if (windowInsets.isVisible(WindowInsetsCompat.Type.navigationBars())) {
// ๋ค๋น๊ฒ์ด์
๋ฐ ๋
ธ์ถ๋จ
} else {
// ๋ค๋น๊ฒ์ด์
๋ฐ ์จ๊ฒจ์ง
}
if (windowInsets.isVisible(WindowInsetsCompat.Type.statusBars())) {
// ์ํ๋ฐ ๋
ธ์ถ๋จ
} else {
// ์ํ๋ฐ ์จ๊ฒจ์ง
}
if (windowInsets.isVisible(WindowInsetsCompat.Type.captionBars())) {
// ์๋ง ๋
ธ์ถ๋จ
} else {
// ์๋ง ์จ๊ฒจ์ง
}
}
Android R ์ด์, ์์คํ ๋ฐ๊ฐ ์จ๊ฒจ์ก์ ๋ ์ฌ์ฉ์ ์ธํฐ๋ ์ ์ผ๋ก ์ ๊น ์์คํ ๋ฐ ๋ ธ์ถ์ํค๊ธฐ
ํ ์คํธ ์ฝ๋๋ Fragment์์ ์์ฑํ๋ค.
val windowInsetsController = WindowCompat.getInsetsController(
requireActivity().window,
requireActivity().window.decorView
)
// Android S(API Level 31)์์ deprecated
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH
// Android S(API Level 31)์์ deprecated
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
// ํ๋ฉด ์๋จ ๋ถ๋ถ์ ์์์ ์๋๋ก ์ธ์ด๋ด๋ฆฌ๋ ์ ์ค์ณ,
// ํน์ ํ๋ฉด ํ๋จ ๋ถ๋ถ์ ์๋์์ ์๋ก ์ธ์ด๋ด๋ฆฌ๋ ์ ์ค์ณ์
// ์์คํ
๋ฐ๊ฐ ํฌ๋ช
ํ๊ฒ ๋
ธ์ถ๋์ด ์ฝํ
์ธ ์์ ์ ๊น ๋ฎ์๋ค๊ฐ ์ฌ๋ผ์ง๋ค.
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
Android R ๋ฏธ๋ง์ GestureDetector๋ก ๊ตฌํํ๋ผ๊ณ ํ๋ค.
https://developer.android.com/training/system-ui/immersive?hl=ko