How to hide the Floating Action Button from Bottom App Bar Layout - android

I'm creating a Bottom App Bar with an Floating Action Button. The App Bar is part of my Main Activity and I want to hide the FAB for some Fragments within the Activity.
I already tried 'View.GONE' and 'fab.hide()'. Then I tried to hide the Fab with following function:
private fun hideFloatingActionButton() {
val params = fab.layoutParams as CoordinatorLayout.LayoutParams
val behavior = params.behavior as FloatingActionButton.Behavior?
if (behavior != null) {
behavior.isAutoHideEnabled = false
}
params.anchorId = View.NO_ID;
params.width = 0;
params.height = 0;
fab.layoutParams = params
fab.hide()
}
My layout.xml:
<androidx.coordinatorlayout.widget.CoordinatorLayout
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"
tools:context=".MainActivity"
android:background="#color/backPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
content
...
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
style="#style/Widget.MaterialComponents.BottomAppBar"
app:navigationIcon="#drawable/ic_burger_menu"
app:fabAlignmentMode="end"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/start_project_day"
app:srcCompat="#drawable/ic_next"
app:layout_anchor="#id/bar"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Just tested out with fab.hide() method and it works. The "logic" to hide the fab should occur in the activity and not in the fragment. The next logic is set in the activity and the hide part is inside the else branch at the end.
navController.addOnDestinationChangedListener { controller, destination, _ ->
bar.animate().translationY(0f)
// First page is main menu
if(controller.graph.startDestination == destination.id){
bar.navigationIcon = icon
bar.fabAlignmentMode = BottomAppBar.FAB_ALIGNMENT_MODE_CENTER
fab?.setImageDrawable(getDrawable(R.drawable.ic_local_wtf))
}else{
// Hide navigation drawer icon
bar.navigationIcon = null
// Move FAB from the center of BottomAppBar to the end of it
bar.fabAlignmentMode = BottomAppBar.FAB_ALIGNMENT_MODE_END
// Replace the action menu
//bar.replaceMenu(bottomappbar_menu_secondary)
invalidateOptionsMenu()
// Change FAB icon
fab?.setImageDrawable(getDrawable(R.drawable.ic_reply_white_24dp))
fab.hide()
}
}

Related

Bugged BottomSheet which is shown when not required

I have a BottomSheet in my App whic have to be shown ONLY at the BottomAppBar navigation button click.
The issue is that in my BottomAppBar i have a FAB button which handles a long click which shows a View and a FAB menu,
when long clicked it make even the BottomSheet expanded when there is no code for it!
Here is my BottomSheet:
<LinearLayout
android:id="#+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:behavior_hideable="true"
android:elevation="8dp"
android:clickable="true"
android:focusable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="#string/bottom_sheet_behavior">
<include layout="#layout/bottom_sheet" />
</LinearLayout>
Here is the only click where i make it EXPANDED_HALF:
bottomAppBar.setNavigationOnClickListener {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}
And here is my longClick which make it fully expanded:
fabNuovo.setOnLongClickListener {
if (View.GONE == fabBGLayout.visibility) {
showFAB()
}else {
closeFAB()
}
}
private fun showFAB() {
fabNuovo.setImageDrawable(ContextCompat.getDrawable(this#LetturaActivity,R.drawable.ic_baseline_close_24))
fabSend.visibility = View.VISIBLE
fabBGLayout.visibility = View.VISIBLE
fabSend.animate().translationY(-120F)
}
private fun closeFAB() {
fabNuovo.setImageDrawable(ContextCompat.getDrawable(this#LetturaActivity,R.drawable.ic_baseline_done_24))
fabBGLayout.visibility = View.GONE
fabSend.visibility = View.GONE
fabSend.animate().translationY(0f)
}
EDIT:
It's not expanded for really as it doesn't cast any callback in BottomSheetCallback...
And even if i click to dismiss the FAB menu it's expanded if not and collapsed if expanded...
EDIT2:
The issue is surely given from one of the following lines in showFAB and closeFAB:
fabSend.visibility = View.VISIBLE
fabBGLayout.visibility = View.VISIBLE
fabSend.animate().translationY(-120F)

How i can set Half Expanded state for my BottomSheet

I have layout with bottom sheet.
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="#color/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main_weather_map" />
<include layout="#layout/bottom_sheet" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Bottom sheet layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:clipToPadding="true"
app:behavior_peekHeight="80dp"
app:layout_behavior="#string/bottom_sheet_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/weather_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
tools:listitem="#layout/item_weather" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
It is necessary for me that my bottom sheet opens first half, and after re-dragging it opens to full screen. How is it done in google maps app. But I have no idea how to do this.
It is better to use the framework with its full potential. As official documentation states for method setFitToContents :
Sets whether the height of the expanded sheet is determined by the height of its contents, or if it is expanded in two stages (half the height of the parent
container, full height of parent container). Default value is true.
So all you need is set setFitToContent to false with:
behavior = BottomSheetBehavior.from(your_bottom_sheet_xml)
behavior.isFitToContents = false
behavior.halfExpandedRatio = 0.6f
With this 3-line-code the bottom sheet will expand till 60% of the screen at first, and afterwards it will fully expand to 100%.
Hope it helps!
Just set BottomSheetBehaivor state to BottomSheetBehavior.STATE_HALF_EXPANDED.
Also if you need after full expanding let user again go back to half expanded mode, you need to set peek height to half of window height.
val bottomSheetBehavior = BottomSheetBehavior.from<NestedScrollView>(bottom_sheet)
val metrics = resources.displayMetrics
bottomSheetBehavior.peekHeight = metrics.heightPixels / 2
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
I have tried the #Massab and #HeyAlex but didn't match my desired behavior.
With the following solution in kotlin, if your bottomsheet sliding is near the expanded state, it stays expanded, if is near the half state, stays at half and if it's near collapsed, it stays collapsed:
val bottomSheet = view.findViewById<View>(R.id.bottom_sheet1)
val mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
mBottomSheetBehavior.addBottomSheetCallback(object: BottomSheetBehavior.BottomSheetCallback(){
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val upperState = 0.66
val lowerState = 0.33
if (bottomSheetEventsFilterBehavior.state == BottomSheetBehavior.STATE_SETTLING ) {
if(slideOffset >= upperState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
if(slideOffset > lowerState && slideOffset < upperState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}
if(slideOffset <= lowerState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
})
Although this question has been answered, but just got another way to implement this behavior so sharing for others.
Create a global variable and initialize it with the default state of your BottomSheetBehavior, like
int state = BottomSheetBehavior.STATE_COLLAPSED;
Then, in BottomSheetBehavior.BottomSheetCallback update your state variable to the current state
and in
BottomSheetBehavior.STATE_DRAGGING, if state is not half expanded,
set the state to BottomSheetBehavior.STATE_HALF_EXPANDED
sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View view, int i) {
switch (i) {
case BottomSheetBehavior.STATE_COLLAPSED:
state = BottomSheetBehavior.STATE_COLLAPSED;
binder.imgRefresh.setVisibility(View.GONE);
break;
case BottomSheetBehavior.STATE_EXPANDED:
binder.imgRefresh.setVisibility(View.VISIBLE);
state = BottomSheetBehavior.STATE_EXPANDED;
break;
case BottomSheetBehavior.STATE_DRAGGING:
if (state != BottomSheetBehavior.STATE_HALF_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
}
break;
case BottomSheetBehavior.STATE_HALF_EXPANDED:
state = BottomSheetBehavior.STATE_HALF_EXPANDED;
break;
}
}
#Override
public void onSlide(#NonNull View view, float v) {
binder.viewExtender.setAlpha(1 - v);
}
});
This will make your BottomSheet to take three steps , i.e., Collapsed, Half Expanded, Expanded.
Hope it can help someone!
class BottomSheetFragment : BottomSheetDialogFragment() {
/* inside of your Bottom Sheet Dialog Fragment */
override fun onStart() {
super.onStart()
BottomSheetBehavior.from(requireView().parent as View).apply {
state = BottomSheetBehavior.STATE_HALF_EXPANDED
}
}
}
Use this block in onCreateView before returning root view
dialog!!.setOnShowListener { dialog ->
val d = dialog as BottomSheetDialog
BottomSheetBehavior.from(requireView().parent as View).apply {
state = BottomSheetBehavior.STATE_EXPANDED
}
}

OnApplyWindowInsetsListener gives systemWindowInsetBottom that is always 0

systemWindowInsetBottom AND stableInsetBottom are both always 0
I have an Activity, that has a background texture, and I am using FLAG_LAYOUT_NO_LIMITS to let that background go behind the status and navigation bar. But I don't want the other contents of the view to go behind those system UI components.
At first I thought of using resources.getIdentifier("navigation_bar_height", "dimen", "android") to get the height of the navigation bar, but that's just the default height of the navigation bar, so it won't work on devices where the user has hidden the navigation bar. (Samsung devices)
Then I found out about WindowInsets and android:fitsSystemWindows="true"
It works for the status bar, but it does not work for the navigation bar.
In my Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//These 2 flags don't seem to change anything
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR)
//This flag is required so the background can go behind the navbar
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.setOnApplyWindowInsetsListener { _, insets ->
val topTextViewParams = rootView.tvTop.layoutParams as ViewGroup.MarginLayoutParams
topTextViewParams.topMargin = insets.systemWindowInsetTop
val bottomTextViewParams = rootView.tvBottom.layoutParams as ViewGroup.MarginLayoutParams
bottomTextViewParams.bottomMargin = insets.systemWindowInsetBottom //Inset is always 0
insets.consumeSystemWindowInsets()
}
}
And my layout
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:id="#+id/rootView"
android:background="#color/colorPrimary"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tvBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Text aligned to bottom of layout with no margin"/>
<TextView
android:id="#+id/tvTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="Text aligned to top of layout with no margin"/>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Example screenshots from Nexus 5x Emulator running API 28. Getting same results on my actual device running API 26.
What do I have to do to get the actual size of the navigation bar, if it is present?
I spend like 3 hours researching this before I posted and then 5 minutes after I posted.
Those 5 minutes were very fruitful, because I found this post, which led me to try adding:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
To my AppTheme, which worked.
So, if you're trying to do this, make sure you:
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val childCount = childCount
for (index in 0 until childCount)
getChildAt(index).dispatchApplyWindowInsets(insets)
// let children know about WindowInsets
return insets
}
OR
Use a "materialish layout such as DrawerLayout or CoordinatorLayout" like I did in my post.
Make sure to use android:fitsSystemWindows="true"
Make sure to add those properties to your theme.
And finally make to do something in your setOnApplyWindowInsetsListener
Here's what I had to do to get both completely transparent status bar and navigation bar, with insets applied:
My root view is a ContstraintLayout. Somehow it's working even without fitsSystemWindows and I'm getting the insets for both the top and bottom, which I've applied to my Toolbar and FrameLayout margins.
In the theme:
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:navigationBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
setImmersive function in Activity:
I've created this function to apply the insets and window flags required to achieve the immersive look for a layout which can have:
Root view
Top view
Content
Bottom view
/**
* Apply immersive mode to this activity
* #param rootView the root layout which will receive the window insets
* #param topView the top view to apply insets to (optional)
* #param bottomView the bottom view to apply insets to (optional)
*/
fun setImmersive(rootView: ViewGroup, topView: View? = null, bottomView: View? = null) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
rootView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
bottomView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
rootView.setOnApplyWindowInsetsListener { _, insets ->
Log.d(javaClass.simpleName + " windowInsets", insets.toString())
// Apply the top insets
if (topView != null) {
insets.systemWindowInsetTop.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetTop $this")
val layoutParams = topView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = this
topView.layoutParams = layoutParams
}
}
}
// Apply the bottom insets
if (bottomView != null) {
insets.systemWindowInsetBottom.apply {
if (this > 0) {
Log.d(javaClass.simpleName, "applying windowInsetBottom $this")
val layoutParams = bottomView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.bottomMargin = this
bottomView.layoutParams = layoutParams
}
}
}
insets.consumeSystemWindowInsets()
}
}
Call this function in your onCreate eg.:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.brand_activity)
setImmersive(root_view, topView = toolbar, bottomView = root_content)
}
The OnApplyWindowInsetsListener on the root view was getting called twice, once with the correct insets WindowInsets{systemWindowInsets=Rect(0, 98 - 0, 168) and again with 0 insets WindowInsets{systemWindowInsets=Rect(0, 0 - 0, 0). So I'm only setting margins on the non-zero insets.
In the layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root_view">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/root_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/toolbar_layout"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="#+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/toolbar_title"
android:textStyle="bold"
android:layout_gravity="center" />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Android 'back' action on Toolbar with Navigation Drawer

Please help with this, I've been going around in circles for hours!
I have a navigation drawer set up and a toolbar (see code below)
I CAN NOT get the back/home function to work, as clicking it results in opening the drawer.
This is in my MainActivity, called during OnCreate.
private fun initialiseViews() {
// Initialise the action bar as the XML toolbar, and set the Title as Dashboard
setSupportActionBar(toolbar)
supportActionBar!!.title = "Dashboard"
// Set-up the NavigationView and its listener
nav_view.setNavigationItemSelectedListener(this)
// Sets the hamburger toggle and its actions for the toolbar
val toggle = ActionBarDrawerToggle(
this, //host activity
drawer_layout, //Drawer Layout object
toolbar, // Toolbar Object
R.string.nav_open, //description for accessibility
R.string.nav_closed //description for accessibility
)
// Set the sync-state and draw-listener to the toggle (hamburger)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
}
The following is within the OnCreateView method of my fragments...
(activity as AppCompatActivity).supportActionBar!!.title = "About"
(activity as MainActivity).supportActionBar!!.setHomeButtonEnabled(true)
(activity as MainActivity).supportActionBar!!.setDisplayHomeAsUpEnabled(true)
The navigation drawer works fine. Changing the title of my toolbar works fine. The hamburger icon is changed to a back arrow within the fragment just fine...
However, each time I press the back arrow, it opens the drawer... kind of as if a listener for the drawer is above the back arrow...
Implementing any code within OnOptionsItemSelected results in nothing as no call is made to that method, since it just opens the drawer.
Would really appreciate someone to point out the obvious in what I have done wrong.
Thanks.
EDIT
main_activity.xml as requested to view...
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="#drawable/background_graphic">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="#color/colorLightOrange"
android:theme="#style/Theme.AppCompat.Light.DarkActionBar"
app:menu="#menu/toolbar_list_menu"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/not needed for post" />
<android.support.v4.view.ViewPager
android:id="#+id/not needed for post" />
</FrameLayout>
<!-- Navigation Drawer -->
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/navigation_menu" />
Did you try to use something like this to set it like back button?
(activity as MainActivity).supportActionBar!!.setNavigationIcon(R.drawable.back)
(activity as MainActivity).supportActionBar!!.setNavigationOnClickListener {
(activity as MainActivity).supportActionBar!!.onBackPressed()
}
And override your onBackPressed
#Override
public void onBackPressed() {
if (sendBackPressToDrawer()) {
return;
}
if (sendBackPressToFragmentOnTop()) {
return;
}
super.onBackPressed();
if (fragmentManager.getBackStackEntryCount() > 0) {
return;
}
finish();
}

Statusbar is not transparent but white

To test kotlin with anko DSL I decided to start a new proyect in last android studio ide (2.1.3), using kotlin plugin (1.0.3) and latest anko library (0.9)
I used the default proyect Navigation Drawer Activity, so I just had to convert the main xml to anko.
This is the xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<RelativeLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<TextView
android:text="Hello World!"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
And it is working perfectly, as you can see here:
With anko, I tried to copy every detail from the xml, getting this code:
class MainActivityUi: AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
drawerLayout {
id = R.id.drawer_layout
fitsSystemWindows = true
coordinatorLayout {
appBarLayout(R.style.AppTheme_AppBarOverlay) {
toolbar {
id = R.id.toolbar
backgroundColor = colorAttr(R.attr.colorPrimary)
popupTheme = R.style.AppTheme_PopupOverlay
}.lparams(height=dimenAttr(R.attr.actionBarSize),width=matchParent)
}.lparams(width=matchParent)
relativeLayout {
padding = dip(16)
textView("Hello World!")
}.lparams(height=matchParent,width=matchParent) {
behavior = AppBarLayout.ScrollingViewBehavior()
}
}.lparams(height=matchParent,width=matchParent)
navigationView {
id = R.id.nav_view
inflateHeaderView(R.layout.nav_header_main)
inflateMenu(R.menu.activity_main_drawer)
}.lparams(height=matchParent) {
gravity = Gravity.START
fitsSystemWindows = true
}
}
}
}
And instead, I'm getting this white statusbar:
The only changes I did was in the MainActivity change the setContentView(R.layout.activity_main), to MainActivityUi.setContentView(this).
So, my question is, why is this happening when they are the same views and layouts? and how can I fix that?
EDIT: I'm using the default proyect that it's created when in Android Studio you choose new proyect, and then you choose DrawerNavigationActivity. If in setContentView I choose to show the xml's view, the statusbar is blue (first screenshot), but if I choose to show the anko's view I get the white statusbar.
In both cases, I'm using same themes, colors, etc, and when using the xml layout, everything is working perfectly, so it must be an anko's problem
Try to do
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
inside onCreate()
it worked for me
Reference
EDIT:
Also My Code
drawerLayout {
lparams(width = matchParent, height = matchParent)
coordinatorLayout {
setPadding(0, dip(24), 0, 0)
appBarLayout {
toolbar {
backgroundColor = primaryColor
setTitleTextColor(primaryColorText)
}.lparams(width = matchParent, height = dip(toolbar_size))
}.lparams(width = matchParent, height = dip(toolbar_size))
}.lparams(width = matchParent, height = matchParent)
navigationView {
}.lparams(width = dip(302), height = matchParent) {
gravity = Gravity.START
}
}
EDIT 2:
By looking at the source code of androidx, they add some code to handle "fitsSystemWindows". We can copy and paste to archive the same effect. Although Anko is dead, it still useful to create Drawerlayout programmatically (and with any other DSL library)
if (ViewCompat.getFitsSystemWindows(this)) {
if (Build.VERSION.SDK_INT >= 21) {
setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
final DrawerLayout drawerLayout = (DrawerLayout) view;
drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
return insets.consumeSystemWindowInsets();
}
});
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS);
try {
mStatusBarBackground = a.getDrawable(0);
} finally {
a.recycle();
}
} else {
mStatusBarBackground = null;
}
}
You're wrong thinking that the status bar is transparent by default.
According to this image
taken from Android Developers Reference. Check: https://developer.android.com/training/material/theme.html
the status bar color depends on what you have defined in colors.xml or styles.xml in values folder as colorPrimaryDark, so it's not transparent.
Your problem is not white color in status bar which is correct for transparency, but not enough knowledge of using themes in Android applications.
EDIT: Changing status bar color (Java):
Window window = activity.getWindow();
// clear FLAG_TRANSLUCENT_STATUS flag:
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// finally change the color
window.setStatusBarColor(activity.getResources().getColor(R.color.my_statusbar_color));
or
public void setStatusBarColor(View statusBar,int color){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//status bar height
int actionBarHeight = getActionBarHeight();
int statusBarHeight = getStatusBarHeight();
//action bar height
statusBar.getLayoutParams().height = actionBarHeight + statusBarHeight;
statusBar.setBackgroundColor(color);
}
}
Hope it will help
It is not your statusbar color issue. Correct me if I am wrong, I believe you are using the Cyanogenmod OS 13.0 edition by the looks of your battery symbol. Switch it back to the default theme in your themes section. Then report back if the issue still persists with your colors.xml file.
Refer this link here for your Kotlin translucent status bar issue.
https://github.com/fython/MaterialStatusBarCompat

Categories

Resources