I try to handle insets by setting ViewCompat.setOnApplyWindowInsetsListener
on attached view, but listener is not called.
I'm confused, because when i apply insets listener to decorView
, it works:
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
Toast.makeText(this, "INSETS HANDLED", Toast.LENGTH_LONG).show()
insets
}
But when i apply insets listener to activity root view (i do it in same place), it's not working:
ViewCompat.setOnApplyWindowInsetsListener(main_root) { v, insets ->
Toast.makeText(this, "INSETS HANDLED", Toast.LENGTH_LONG).show()
insets
}
I have a single activity app, and i set both this listeners when onCreate()
method called.
I know i can get insets from first example and cache them, but now i need second code works, because i need this library works:
https://github.com/chrisbanes/insetter
It's have api like:
Insetter.builder()
.applySystemWindowInsetsToPadding(Side.LEFT)
.applyToView(main_bottom_nav)
It provide easy way to apply insets to your views. But it did't work.
I debug it and i saw that under the hood this library set listener to view like i try to do in a second code example, so when i get the reason why my listeners are not trigger, i think i can make this library work.
My minds are:
I don't rly understand what's happening. It's very strange for me that decorView has insets, but activity root is not. By logic, it's possible only when someone between decorView and activity view handle and consume insets, but is sounds strange: activity root view must to know about insets.
What i tried to do(see code), and it's not help:
- Change root ViewGroup from ConstraintLayout ro Frame/Linear/RelativeLayout.
- Add/remove
fitsSystemWindows
attribute to activity root ViewGroup. In fact i planning to remove insets at all to make a fullscreen application, so i don't think i need this flag enabled. - Change windowSoftInputMode of activity: it's adjustResize now.
- Call
requestApplyInsets()
on target view before and after listener applied. - Downgrade androidx.core:core-ktx and androidx.activity:activity-ktx to stable versions.
Code:
activity.xml: https://github.com/KirstenLy/AdviceCollector/blob/master/app/src/main/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_main_content">
<ImageView
android:id="@+id/main_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/wise"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/main_bottom_nav"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/color_main_content"
android:elevation="@dimen/elevation_4"
android:translationZ="@dimen/elevation_4"
android:visibility="gone"
app:labelVisibilityMode="unlabeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_navigation_menu" />
<!-- Helper view to show snackBar: need because of transparent navigation bar -->
<View
android:id="@+id/main_snackbar_anchor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- No internet error section -->
<ImageView
android:id="@+id/main_error_internet_icon"
android:layout_width="@dimen/image_size_96"
android:layout_height="@dimen/image_size_96"
app:layout_constraintBottom_toTopOf="@+id/main_error_internet_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:srcCompat="@drawable/ic_wifi" />
<TextView
android:id="@+id/main_error_internet_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:lines="3"
android:padding="@dimen/padding_16"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@+id/main_error_internet_retry_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/main_error_internet_icon"
tools:text="@string/main_activity_error_loading" />
<com.google.android.material.button.MaterialButton
android:id="@+id/main_error_internet_retry_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/dark_blue"
android:padding="@dimen/padding_16"
android:text="@string/default_retry"
app:icon="@drawable/ic_autorenew"
app:iconGravity="textEnd"
app:iconPadding="@dimen/padding_4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/main_error_internet_text" />
<androidx.constraintlayout.widget.Group
android:id="@+id/main_error_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="main_error_internet_icon,main_error_internet_retry_button,main_error_internet_text" />
<FrameLayout
android:id="@+id/main_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/main_bottom_nav"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt: https://github.com/KirstenLy/AdviceCollector/blob/master/app/src/main/java/com/kirstenly/advice_collector/ui/activity_main/MainActivity.kt
package com.kirstenly.advice_collector.ui.activity_main
import android.os.Bundle
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.google.android.play.core.review.ReviewManagerFactory
import com.kirstenly.advice_collector.R
import com.kirstenly.advice_collector.Screens
import com.kirstenly.advice_collector.contracts.NavigationEventConsumer
import com.kirstenly.advice_collector.other.helpers.DayNightThemeHelper
import com.kirstenly.advice_collector.other.helpers.InsetHelper
import com.kirstenly.advice_collector.ui.activity_main.router.MainActivityRouter
import com.kirstenly.sdk.extensions.*
import com.kirstenly.sdk.other.navigation.BaseScreen
import dagger.android.support.DaggerAppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import javax.inject.Inject
/** Host activity for application */
class MainActivity : DaggerAppCompatActivity(R.layout.activity_main), NavigationEventConsumer {
@Inject lateinit var router: MainActivityRouter
@Inject lateinit var viewModel: MainActivityViewModel
@Inject lateinit var insetHelper: InsetHelper
@Inject lateinit var dayNightThemeHelper: DayNightThemeHelper
override fun onNavigationEvent(screen: BaseScreen) {
router.navigateTo(screen)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
initViews()
initObservers()
}
private fun initViews() {
ViewCompat.setOnApplyWindowInsetsListener(window.decorView){ v, insets ->
Toast.makeText(this, "INSETS HANDLED", Toast.LENGTH_LONG).show()
insets
}
// main_bottom_nav.applySystemWindowInsetsToMargin(bottom = true, top = true, left = true, consume = true)
// root_root.requestApplyInsetsWhenAttached()
// Insetter.builder()
// .applySystemWindowInsetsToPadding(Side.LEFT)
// .applyToView(main_bottom_nav)
//
// setWindowTransparency { statusBarSize, navigationBarSize ->
// insetHelper.topInset = statusBarSize
// insetHelper.bottomInset = navigationBarSize
// main_bottom_nav.updatePaddingFromPx(bottom = navigationBarSize)
// main_snackbar_anchor.layoutParams.height = navigationBarSize
// }
with(main_bottom_nav) {
setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.bottom_home -> router.navigateTo(Screens.HomeScreen)
R.id.bottom_favorite -> router.navigateTo(Screens.FavoriteAdvicesScreen)
R.id.bottom_login -> router.navigateToLoginOrUserAdvices()
R.id.bottom_new_advice -> router.navigateToNewAdvice()
R.id.bottom_day_night -> dayNightThemeHelper.setDayOrNightMode()
}
true
}
removeItemIconTintList()
setIconOnItem(R.id.bottom_day_night, dayNightThemeHelper.getDayOrNightModeIcon())
}
main_error_internet_retry_button.setOnClickListener {
viewModel.retryInternetConnection()
}
}
private fun initObservers() {
viewModel.errorStateLiveData.observe(this, { errorState ->
main_error_group.isVisible = errorState != ErrorState.NONE
main_icon.isVisible = errorState == ErrorState.NONE
main_error_internet_retry_button.isEnabled = errorState != ErrorState.RETRYING
val errorText = when (errorState) {
ErrorState.RETRYING -> getString(R.string.main_activity_error_retrying)
ErrorState.NO_INTERNET_ERROR -> getString(R.string.main_activity_error_loading)
ErrorState.UPDATE_DATA_ERROR -> getString(R.string.main_activity_error_update)
ErrorState.NONE -> null
}
main_error_internet_text.text = errorText
})
viewModel.navigationEventLiveData.observe(this, router::navigateTo)
viewModel.isDataPreparedLiveData.observe(this, { isDataPrepared ->
main_icon.isGone = isDataPrepared
})
}
// TODO: Поддержать inAppReview, будет возможно только после залива в GP
private fun initAppReview() {
val manager = ReviewManagerFactory.create(this)
val request = manager.requestReviewFlow()
request.addOnCompleteListener { request ->
if (request.isSuccessful) {
// We got the ReviewInfo object
val reviewInfo = request.result
val flow = manager.launchReviewFlow(this, reviewInfo)
flow.addOnCompleteListener { a ->
a.isComplete
// The flow has finished. The API does not indicate whether the user
// reviewed or not, or even whether the review dialog was shown. Thus, no
// matter the result, we continue our app flow.
}
} else {
// There was some problem, continue regardless of the result.
}
}
}
override fun onBackPressed() {
if (!router.handleOnBackPressedByCurrentFragment()) {
if (!supportFragmentManager.isBackStackEmpty()) {
super.onBackPressed()
} else {
finish()
}
}
}
}