FullScreen immersive activity with hide show system UI (action bar and status bar) on user interaction FullScreenBaseActivity - does everything automatically. You only call setUpToolbar in onCreate and assign mContentView and mControlsView (optionally)
<style name="FullscreenTheme" parent="AppTheme.NoActionBar">
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowBackground">@null</item>
<item name="metaButtonBarStyle">?android:attr/buttonBarStyle</item>
<item name="metaButtonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
</style>
<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
<item name="android:background">@color/blackOverlay</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".QuizActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black" />
// It's important, that toolbar is lower in code than content.
// It'll make it appeare over content
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/appBar"
android:background="@android:color/transparent"
android:theme="@style/AppTheme.AppBarOverlay"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/blackOverlay" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
abstract class FullscreenBaseActivity : AppCompatActivity() {
abstract var mContentView: View?
abstract var mControlsView: View?
private val mHideHandler = Handler()
@SuppressLint("InlinedApi")
private val mHidePart2Runnable = Runnable {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}
private val mShowPart2Runnable = Runnable {
// Delayed display of UI elements
showActionBar()
}
private var mVisible: Boolean = false
private val mHideRunnable = Runnable { hide() }
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
private val mDelayHideTouchListener = View.OnTouchListener { view, motionEvent ->
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS)
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myDecorView = window.decorView
myDecorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(this, R.color.blackOverlayDark)
}
mVisible = true
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
// findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener)
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100)
}
// Important method. Call it in onCreate()
fun setUpToolbar(toolbar: Toolbar, title: String) {
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = title
val lp = toolbar.layoutParams as AppBarLayout.LayoutParams
lp.setMargins(0, getStatusBarHeight(), 0, 0)
}
private fun getStatusBarHeight(): Int {
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
fun toggle() {
if (mVisible) {
hide()
} else {
show()
}
}
fun hide() {
// Hide UI first
hideActionBar()
mControlsView?.visibility = View.GONE
mVisible = false
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable)
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY.toLong())
}
@SuppressLint("InlinedApi")
fun show() {
// Show the system bar
mContentView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
mVisible = true
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable)
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY.toLong())
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS)
}
}
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
fun delayedHide(delayMillis: Int) {
mHideHandler.removeCallbacks(mHideRunnable)
mHideHandler.postDelayed(mHideRunnable, delayMillis.toLong())
}
private fun hideActionBar() {
val ab = supportActionBar
if (ab != null && ab.isShowing) {
if (appBar != null) {
appBar.animate().translationY(-appBar.height.toFloat()).setDuration(200L)
.withEndAction({ ab.hide() }).start()
} else ab.hide()
}
}
private fun showActionBar() {
val ab = supportActionBar
if (ab != null && !ab.isShowing) {
ab.show()
if (appBar != null) {
appBar.animate().translationY(0f).setDuration(200L).start()
}
}
}
companion object {
/**
* Whether or not the system UI should be auto-hidden after
* [.AUTO_HIDE_DELAY_MILLIS] milliseconds.
*/
private val AUTO_HIDE = true
/**
* If [.AUTO_HIDE] is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private val AUTO_HIDE_DELAY_MILLIS = 3000
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private val UI_ANIMATION_DELAY = 200
}
}
import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.support.design.widget.AppBarLayout
import android.support.v4.content.ContextCompat
import android.support.v4.view.ViewPager
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.view.WindowManager
import kotlinx.android.synthetic.main.fragment_game.*
import us.kostenko.mnemonikon.R
import us.kostenko.mnemonikon.codes.utility.Image
import java.util.Collections.shuffle
import java.util.concurrent.TimeUnit
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
val EXTRA_IMAGES = "extraImages"
class FullscreenActivity : AppCompatActivity() {
private lateinit var images: java.util.ArrayList<Image>
private lateinit var myViewPagerAdapter: GamePagerAdapter
private var selectedPosition = 0
var errors = 0
var startTime: Long = 0
var totalTime: Long = 0
var itemsCount = 0
var random = true
// page change listener
internal var viewPagerPageChangeListener = object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
trackShowingTime()
}
}
private val mHideHandler = Handler()
@SuppressLint("InlinedApi")
private val mHidePart2Runnable = Runnable {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
viewPager!!.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}
private val mShowPart2Runnable = Runnable {
// Delayed display of UI elements
showActionBar()
}
private var mVisible: Boolean = false
private val mHideRunnable = Runnable { hide() }
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
private val mDelayHideTouchListener = View.OnTouchListener { view, motionEvent ->
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS)
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_game)
val myDecorView = window.decorView
myDecorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(this, R.color.blackOverlayDark)
}
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toolbar.title = getString(R.id.codes_title)
val lp = toolbar.layoutParams as AppBarLayout.LayoutParams
lp.setMargins(0, getStatusBarHeight(), 0, 0)
mVisible = true
images = intent.getParcelableArrayListExtra(EXTRA_IMAGES)
if (random) shuffle(images)
// selectedPosition = intent.extras.getInt()
myViewPagerAdapter = GamePagerAdapter(images, { isCorrect ->
if (isCorrect) nextItem()
else errors += 1
}, { toggle() })
viewPager.adapter = myViewPagerAdapter
viewPager.addOnPageChangeListener(viewPagerPageChangeListener)
setCurrentItem(selectedPosition)
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
// findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener)
}
private fun setCurrentItem(position: Int) {
viewPager.setCurrentItem(position, false)
}
private fun nextItem() {
setCurrentItem(viewPager.currentItem + 1)
}
private fun trackShowingTime() {
val finishTime: Long = System.nanoTime()
if (itemsCount > 0) this.totalTime += TimeUnit.NANOSECONDS.toMillis(finishTime - startTime)
Log.d("GameFragment", "trackShowingTime(), finishTime: $finishTime, startTime: $startTime, totalTime: ${this.totalTime}")
startTime = finishTime
itemsCount += 1
}
private fun getStatusBarHeight(): Int {
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
fun hideActionBar() {
val ab = supportActionBar
if (ab != null && ab.isShowing) {
if (appBar != null) {
appBar.animate().translationY(-appBar.height.toFloat()).setDuration(200L)
.withEndAction({ ab.hide() }).start()
} else ab.hide()
}
}
fun showActionBar() {
val ab = supportActionBar
if (ab != null && !ab.isShowing) {
ab.show()
if (appBar != null) {
appBar.animate().translationY(0f).setDuration(200L).start()
}
}
}
/* Not mine */
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100)
}
private fun toggle() {
if (mVisible) {
hide()
} else {
show()
}
}
private fun hide() {
// Hide UI first
// val actionBar = supportActionBar
// actionBar?.hide()
hideActionBar()
mVisible = false
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable)
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY.toLong())
}
@SuppressLint("InlinedApi")
private fun show() {
// Show the system bar
viewPager.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
mVisible = true
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable)
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY.toLong())
}
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private fun delayedHide(delayMillis: Int) {
mHideHandler.removeCallbacks(mHideRunnable)
mHideHandler.postDelayed(mHideRunnable, delayMillis.toLong())
}
companion object {
/**
* Whether or not the system UI should be auto-hidden after
* [.AUTO_HIDE_DELAY_MILLIS] milliseconds.
*/
private val AUTO_HIDE = true
/**
* If [.AUTO_HIDE] is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private val AUTO_HIDE_DELAY_MILLIS = 3000
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private val UI_ANIMATION_DELAY = 200
}
}
<activity
android:name=".codes.game.FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_fullscreen"
android:parentActivityName=".QuizActivity"
android:theme="@style/FullscreenTheme">
</activity>