Fix window insets handling when in landscape mode

To avoid code duplication, insets handling has been moved to a separate interface.
This commit is contained in:
lynxnb 2022-11-10 16:48:25 +01:00 committed by Mark Collins
parent ab6c5f4c50
commit 163f4f2014
5 changed files with 101 additions and 31 deletions

View File

@ -18,7 +18,9 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.use import androidx.core.content.res.use
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.* import androidx.core.view.WindowCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -35,6 +37,7 @@ import emu.skyline.loader.LoaderResult
import emu.skyline.loader.RomFormat import emu.skyline.loader.RomFormat
import emu.skyline.provider.DocumentsProvider import emu.skyline.provider.DocumentsProvider
import emu.skyline.utils.PreferenceSettings import emu.skyline.utils.PreferenceSettings
import emu.skyline.utils.WindowInsetsHelper
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.ceil import kotlin.math.ceil
@ -100,12 +103,7 @@ class MainActivity : AppCompatActivity() {
setContentView(binding.root) setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
// Apply inset padding to the app list recycler view to avoid navigation bar overlap WindowInsetsHelper.applyToActivity(binding.root, binding.appList)
ViewCompat.setOnApplyWindowInsetsListener(binding.appList) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(bottom = insets.bottom)
WindowInsetsCompat.CONSUMED
}
PreferenceManager.setDefaultValues(this, R.xml.preferences, false) PreferenceManager.setDefaultValues(this, R.xml.preferences, false)

View File

@ -16,6 +16,7 @@ import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import emu.skyline.databinding.SettingsActivityBinding import emu.skyline.databinding.SettingsActivityBinding
import emu.skyline.preference.IntegerListPreference import emu.skyline.preference.IntegerListPreference
import emu.skyline.utils.WindowInsetsHelper
class SettingsActivity : AppCompatActivity() { class SettingsActivity : AppCompatActivity() {
val binding by lazy { SettingsActivityBinding.inflate(layoutInflater) } val binding by lazy { SettingsActivityBinding.inflate(layoutInflater) }
@ -33,6 +34,7 @@ class SettingsActivity : AppCompatActivity() {
setContentView(binding.root) setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsHelper.applyToActivity(binding.root)
setSupportActionBar(binding.titlebar.toolbar) setSupportActionBar(binding.titlebar.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
@ -81,15 +83,9 @@ class SettingsActivity : AppCompatActivity() {
} }
override fun onViewCreated(view : View, savedInstanceState : Bundle?) { override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
val recyclerView = view.findViewById<View>(R.id.recycler_view)
// Apply inset padding to the settings recycler view to avoid navigation bar overlap
ViewCompat.setOnApplyWindowInsetsListener(recyclerView) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(bottom = insets.bottom)
WindowInsetsCompat.CONSUMED
}
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<View>(R.id.recycler_view)
WindowInsetsHelper.setPadding(recyclerView, bottom = true)
} }
/** /**

View File

@ -12,7 +12,8 @@ import android.view.KeyEvent
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.* import androidx.core.view.WindowCompat
import androidx.core.view.marginTop
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -29,6 +30,7 @@ import emu.skyline.input.dialog.RumbleDialog
import emu.skyline.input.dialog.StickDialog import emu.skyline.input.dialog.StickDialog
import emu.skyline.input.onscreen.OnScreenEditActivity import emu.skyline.input.onscreen.OnScreenEditActivity
import emu.skyline.utils.PreferenceSettings import emu.skyline.utils.PreferenceSettings
import emu.skyline.utils.WindowInsetsHelper
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -173,12 +175,7 @@ class ControllerActivity : AppCompatActivity() {
setContentView(binding.root) setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
// Apply inset padding to the controller list recycler view to avoid navigation bar overlap WindowInsetsHelper.applyToActivity(binding.root, binding.controllerList)
ViewCompat.setOnApplyWindowInsetsListener(binding.controllerList) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(bottom = insets.bottom)
WindowInsetsCompat.CONSUMED
}
setSupportActionBar(binding.titlebar.toolbar) setSupportActionBar(binding.titlebar.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)

View File

@ -12,10 +12,7 @@ import android.view.ViewTreeObserver
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -29,6 +26,7 @@ import emu.skyline.databinding.GpuDriverActivityBinding
import emu.skyline.utils.GpuDriverHelper import emu.skyline.utils.GpuDriverHelper
import emu.skyline.utils.GpuDriverInstallResult import emu.skyline.utils.GpuDriverInstallResult
import emu.skyline.utils.PreferenceSettings import emu.skyline.utils.PreferenceSettings
import emu.skyline.utils.WindowInsetsHelper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -127,12 +125,8 @@ class GpuDriverActivity : AppCompatActivity() {
setContentView(binding.root) setContentView(binding.root)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
// Apply inset padding to the driver list recycler view to avoid navigation bar overlap WindowInsetsHelper.applyToActivity(binding.root, binding.driverList)
ViewCompat.setOnApplyWindowInsetsListener(binding.driverList) { view, windowInsets -> WindowInsetsHelper.addMargin(binding.addDriverButton, bottom = true)
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(bottom = insets.bottom)
WindowInsetsCompat.CONSUMED
}
setSupportActionBar(binding.titlebar.toolbar) setSupportActionBar(binding.titlebar.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)

View File

@ -0,0 +1,85 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
package emu.skyline.utils
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
/**
* An interface to easily add window insets handling to any layout
*/
interface WindowInsetsHelper {
companion object {
/**
* Convenience method to setup insets for most Activities with a single call
* @param rootView The root view of the layout
* @param listView The list view of the layout
*/
fun applyToActivity(rootView : View, listView : View? = null) {
// Apply margin to the root view to avoid overlapping system bar in landscape mode
// Don't consume insets in the root view so that child views can apply them
setMargin(rootView, consume = false, left = true, right = true)
// Apply padding to the list view to avoid navigation bar overlap at the bottom
listView?.let { addPadding(it, bottom = true) }
}
fun setMargin(view : View, consume : Boolean = true, left : Boolean = false, top : Boolean = false, right : Boolean = false, bottom : Boolean = false) {
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
if (left) leftMargin = insets.left
if (top) topMargin = insets.top
if (right) rightMargin = insets.right
if (bottom) bottomMargin = insets.bottom
}
if (consume) WindowInsetsCompat.CONSUMED else windowInsets
}
}
fun addMargin(view : View, consume : Boolean = true, left : Boolean = false, top : Boolean = false, right : Boolean = false, bottom : Boolean = false) {
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
if (left) leftMargin += insets.left
if (top) topMargin += insets.top
if (right) rightMargin += insets.right
if (bottom) bottomMargin += insets.bottom
}
if (consume) WindowInsetsCompat.CONSUMED else windowInsets
}
}
fun setPadding(view : View, consume : Boolean = true, left : Boolean = false, top : Boolean = false, right : Boolean = false, bottom : Boolean = false) {
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(
if (left) insets.left else v.paddingLeft,
if (top) insets.top else v.paddingTop,
if (right) insets.right else v.paddingRight,
if (bottom) insets.bottom else v.paddingBottom
)
if (consume) WindowInsetsCompat.CONSUMED else windowInsets
}
}
fun addPadding(view : View, consume : Boolean = true, left : Boolean = false, top : Boolean = false, right : Boolean = false, bottom : Boolean = false) {
ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(
if (left) insets.left + v.paddingLeft else v.paddingLeft,
if (top) insets.top + v.paddingTop else v.paddingTop,
if (right) insets.right + v.paddingRight else v.paddingRight,
if (bottom) insets.bottom + v.paddingBottom else v.paddingBottom
)
if (consume) WindowInsetsCompat.CONSUMED else windowInsets
}
}
}
}