Skip to content

Instantly share code, notes, and snippets.

/**
* Registers a listener which is informed when UI is shown (true) or hidden (false).
*/
fun Window.addSystemUIVisibilityListener(visibilityListener: (Boolean) -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
decorView.setOnApplyWindowInsetsListener { v, insets ->
val suppliedInsets = v.onApplyWindowInsets(insets)
// only check for statusBars() and navigationBars(), because captionBar() is not always
// available and isVisible() could return false, although showSystemUI() had been called:
visibilityListener(suppliedInsets.isVisible(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()))
/**
* Shows the system bars and returns back from fullscreen.
* @see hideSystemUI
* @see addSystemUIVisibilityListener
*/
fun Activity.showSystemUI() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// show app content in fullscreen, i. e. behind the bars when they are shown (alternative to
// deprecated View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION and View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
window.setDecorFitsSystemWindows(false)
/**
* Should be called from [Activity.onCreate].
* @see hideSystemUI
* @see showSystemUI
*/
fun Activity.showBelowCutout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
}
}
@milhauscz
milhauscz / ExampleSpinnerArrayAdapter.kt
Created April 21, 2021 12:41
Example implementation of MaterialSpinnerAdapter
class ExampleSpinnerArrayAdapter(context: Context, objects: List<ExampleItem>) : MaterialSpinnerAdapter<ExampleItem>(context, objects) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
// implement viewholder pattern
val view: View
// automatically generated binding class
val binding: ExampleItemBinding
if (convertView == null) {
// view is new - we have to inflate the binding object and set it as a tag
binding = ExampleItemBinding.inflate(inflater, parent, false)
view = binding.root
@milhauscz
milhauscz / MaterialSpinnerBindingAdapters.kt
Created April 21, 2021 13:47
Binding adapters for MaterialSpinner
@BindingAdapter("selectedPosition")
fun setSelectedPosition(view: MaterialSpinner, position: Int) {
if (view.selectedPosition != position) {
view.selectedPosition = position
}
}
@InverseBindingAdapter(attribute = "selectedPosition")
fun getSelectedPosition(view: MaterialSpinner): Int {
return view.selectedPosition
@milhauscz
milhauscz / MaterialSpinner.kt
Last active April 21, 2021 13:48
Custom implementation of an Android spinner (combo box) with material theme and data binding support by extending AutocompleteTextView
/**
* Custom implementation of an Android spinner (combo box) with material theme by using AutocompleteTextView.
* Recommended to use together with [MaterialSpinnerAdapter].
*
* Supports listening to and updating the selected position e. g. from a LiveData object bound via
* the `selectedPosition` two-way binding adapter. The empty text value can be bound via 'emptyText'
* attr (custom styleable must be declared in attrs.xml).
*
* If [MaterialSpinnerAdapter] is used, its [MaterialSpinnerAdapter.selectedItemPosition] is
* automatically updated when selection changes.
@milhauscz
milhauscz / attrs.xml
Created April 21, 2021 14:20
Custom emptyText attribute for MaterialSpinner
<resources>
<declare-styleable name="MaterialSpinner">
<attr name="emptyText" format="reference|string" />
</declare-styleable>
</resources>
@milhauscz
milhauscz / example_spinner.xml
Last active April 21, 2021 14:56
Example of an XML layout using MaterialSpinner
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.google.android.material.textfield.TextInputLayout" />
<variable
name="viewModel"
type="com.example.SpinnerViewModel" />
@milhauscz
milhauscz / ExampleItemBindingAdapter.kt
Last active April 21, 2021 15:14
Example of a custom binding adapter for Material Spinner
@BindingAdapter("items")
fun bindItems(view: MaterialSpinner, items: List<ExampleItem>?) {
if (items == null) return
view.setAdapter(ExampleSpinnerArrayAdapter(view.context, items))
}
/**
* Hides the system bars and makes the Activity "fullscreen". If this should be the default
* state it should be called from [Activity.onWindowFocusChanged] if hasFocus is true.
* It is also recommended to take care of cutout areas. The default behavior is that the app shows
* in the cutout area in portrait mode if not in fullscreen mode. This can cause "jumping" if the
* user swipes a system bar to show it. It is recommended to set [WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER],
* call [showBelowCutout] from [Activity.onCreate]
* (see [Android Developers article about cutouts](https://developer.android.com/guide/topics/display-cutout#never_render_content_in_the_display_cutout_area)).
* @see showSystemUI
* @see addSystemUIVisibilityListener