How to add NavHostFragment in a Fragment destination? - android-jetpack

My goal is to understand and use the Navigation component in the best way with a complex navigation architecture (I suppose).
To make the global context, I use a main BottomNavigationBar with 5 items. For the management of the fragments associate, I use the example given by Google : https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample.
But my case is a bit more complex than just a bottom bar. In one of the destinations from one of the fragments launched by the bottom bar, I have another RecyclerView menu and a fragment container to navigate between fragments. I put here the important part of my primary graph :
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.exemple.fragment.MainFragment"
android:label="#string/main_label"
tools:layout="#layout/mainFragment">
<action
android:id="#+id/action_mainFragment_to_goScreen"
app:destination="#id/goScreen">
</action>
</fragment>
<fragment
android:id="#+id/goScreen"
android:name="com.exemple.fragment.GoFragment"
android:label="#string/goLabel"
tools:layout="#layout/fragment_go">
<action
android:id="#+id/action_goScreen_to_mainFragment"
app:destination="#id/mainFragment" />
<argument
android:name="arg1"
app:argType="com.exemple.customType"
android:defaultValue="#null"
app:nullable="true" />
<argument
android:name="arg2"
app:argType="string"
android:defaultValue="#null"
app:nullable="true" />
</fragment>
</navigation>
And the xml with the bottom bar which starts this graph :
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.exemple.MainActivity">
<RelativeLayout
android:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/fake_toolbar"
android:layout_width="0dp"
android:layout_height="0dp"/>
<androidx.fragment.app.FragmentTabHost
android:id="#+id/main_host_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottom_navigation" />
<!-- navigation bottom -->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_alignParentBottom="true"
android:background="#color/navigationBarColor"
app:itemIconTint="#color/textColorNavigationBar"
app:itemTextColor="#color/textColorNavigationBar"
app:menu="#menu/menu_bottom_navigation" />
</RelativeLayout>
</layout>
And here is an example of the graph corresponding to the go fragment (the destination ):
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/go"
app:startDestination="#id/firstGoFragment">
<action android:id="#+id/action_to_firstGoFragment"
app:destination="#id/firstGoFragment"/>
<fragment
android:id="#+id/firstGoFragment"
android:name="com.exemple.go.firstGoFragment"
android:label="#string/firstGoFragmentLabel"
tools:layout="#layout/firstGoFragment" >
</fragment>
<action android:id="#+id/action_to_secondFragment"
app:destination="#id/secondFragment"/>
<fragment
android:id="#+id/secondFragment"
android:name="com.exemple.go.SecondFragment"
android:label="#string/secondFragmentLabel"
tools:layout="#layout/secondFragment" >
</fragment>
</navigation>
The associate xml is :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorGreyLight"
android:clickable="true"
android:focusable="true">
<RelativeLayout
android:id="#+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/quit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:paddingBottom="15dp"
android:paddingEnd="15dp"
android:paddingTop="15dp"
app:srcCompat="#drawable/ic_quit_white" />
<com.teedji.mobeelity.custom.CustomTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="#string/go"
android:textColor="#color/colorWhite"
android:textSize="17sp"
android:textStyle="bold" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/goMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#color/colorWhite"
android:overScrollMode="never"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout3" />
<!-- include fragment child container -->
<fragment
android:id="#+id/go_nav_host_fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/goMenu"
app:navGraph="#navigation/go"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Now, to navigate to the go screen I simply use
findNavController().navigate(MainFragmentDirections.actionMainFragmentToGoScreen(arg1, arg2))
or
findNavController().navigate(R.id. action_mainFragment_to_goScreen)
But when I am on the Go fragment, the navController the I find using findNavController() is still the mainFragment one. So the navigate() fonction didn't find the action id. To solve it, I had to change the navHost programaticaly in the GoFragment like this :
override fun onCreate(savedInstanceState: Bundle?) {
Log.i(LOG_TAG, "onCreate")
super.onCreate(savedInstanceState)
if( fragmentManager != null ) {
// If the Nav Host fragment exists, return it
val existingFragment = fragmentManager!!.findFragmentByTag(FRAGMENT_TAG) as NavHostFragment?
existingFragment?.let { navHostGoFragment = it }
// Otherwise, create it and return it.
if ( navHostGoFragment == null) {
navHostGoFragment = NavHostFragment.create(R.navigation.go)
fragmentManager!!.beginTransaction()
.add(R.id.go_nav_host_fragment_container, navHostGoFragment!!, FRAGMENT_TAG)
.commit()
}
}else {
Log.e(LOG_TAG, "fragmentManager is null so I can't find the fragment host")
}
}
and then use navHostGoFragment!!.navController.navigate(R.id.action_to_firstGoFragment) to navigate in the new container
But doing like this, my firstFragment is created twice (I can see it on my logs) and that generate some problems like Cannot add the same observer with different lifecycles for example ( I solve this with adding
if (model.getLiveData().hasObservers()) {
model.getLiveData().removeObserver(observer)
}
before
model.getLiveData().observe(viewLifecycleOwner, observer)
)
But I think I am not doing the Navigation part like I should...
Could you provide any help to make this work more efficiently with stability ?

Try to use go_nav_host_fragment_container.findNavController().navigate(), if you are using Kotlin Android Extensions or findViewById(R.id.go_nav_host_fragment_container).findNavController().navigate(), and see if it works.

Related

onBindViewHolder of RecyclerView inside nestedscrollview is getting invoked for all item at once

I am having a CollapsingToolbar and a bottom navbar as shown:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:fitsSystemWindows="true"
app:layout_constraintBottom_toTopOf="#id/nav_view"
app:layout_constraintTop_toTopOf="parent">
<!-- Scrollable view here -->
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="#dimen/height335"
android:background="#drawable/ic_appbar_bg"
android:fitsSystemWindows="true"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="#color/colorPrimaryDark"
app:toolbarId="#+id/toolbar"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/transparent"
android:contentInsetStart="0dp"
android:contentInsetLeft="0dp"
android:gravity="center"
app:contentInsetEnd="0dp"
app:contentInsetEndWithActions="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="2dp"
app:layout_collapseMode="pin"
app:theme="#style/ToolbarTheme">
<include
android:id="#+id/toolbar_header_view"
layout="#layout/widget_header_view_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:cardDetails="#{viewModel}" />
</androidx.appcompat.widget.Toolbar>
<include
layout="#layout/widget_header"
bind:cardDetails="#{viewModel}" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/swipe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<!-- just a nestedscrollview
override fun onTouchEvent(ev: MotionEvent): Boolean {
return scrollable && super.onTouchEvent(ev)
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return scrollable && super.onInterceptTouchEvent(ev)
}
fun setScrollingEnabled(enabled: Boolean) {
scrollable = enabled
} -->
<com.android.utils.LockableNestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:clipChildren="false"
android:clipToPadding="false"
android:fillViewport="true">
<LinearLayout>
<Some views...
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:layout_width="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_height="match_parent" />
</LinearLayout>
</com.android.utils.LockableNestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="#{()->viewModel.fabClicked()}"
android:src="#drawable/ic_plus"
app:fabCustomSize="#dimen/fab70"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
android:elevation="#dimen/elevation3"
android:paddingTop="#dimen/padding10"
app:itemTextAppearanceActive="#style/BottomNavigationViewTextStyle"
app:itemTextAppearanceInactive="#style/BottomNavigationViewTextStyle"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/nav_view" />
Fragment container will be replaced with fragments when nav bar items are clicked. The issue is that in one of the fragment I have a recyclerview. The onBindView of all the items in the recyclerview is getting invoked all at once. I need to avoid this mainly because I am trying to implement Pagination like this:
override fun onBindViewHolder(holder: TopUpViewHolder, position: Int) {
val item = myDataset[position]
holder.bind(item)
if (position == this.itemCount - 1){
// do your load more task here
viewModel.fetchTopUpData()
}
}
(I tried attaching scroll listener and implement pagination like this. But the canScrollVertically(1) is getting invoked even when the user has not reached the end, probably because of nestedscrollview itself.)
Here is my fragment with recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<data>
<import type="android.view.View" />
<variable
name="viewmodel"
type="com.android.ui.topup.viewmodel.TopUpViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="#dimen/padding15">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/status_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/padding20"
android:visibility="#{viewmodel.headerVisibility}">
<TextView
android:id="#+id/recentLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin20"
android:text="#string/recent_top_ups"
android:textAllCaps="true"
android:textColor="#color/topup_label_text_color"
android:textSize="#dimen/text12"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/viewAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin20"
android:onClick="#{()->viewmodel.viewAllClicked()}"
android:text="#string/view_all"
android:textColor="#color/topup_label_color_orenge"
android:textSize="#dimen/text14"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/topUpRCView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"
android:clipChildren="false"
android:clipToPadding="false"
app:scrollListener="#{viewmodel.scrollListener}" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="#{viewmodel.fetchingFlag?View.VISIBLE:View.GONE}" />
</LinearLayout>
<LinearLayout
android:id="#+id/empty_list"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="#{viewmodel.listEmpty}"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="#drawable/ic_illustration_receipt"/>
<TextView
android:id="#+id/empty_list_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/you_have_no_topup_requests"
android:fontFamily="#font/colfaxregular"
android:textColor="#333547"
android:layout_marginTop="36dp"
android:textSize="#dimen/text16"
android:alpha=".3"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Things that I have tried:
Added android:nestedScrollingEnabled="false" in the recyclerview
Added app:layout_behavior="#string/appbar_scrolling_view_behavior"
Changed the height of recyclerview to match_parent wrap_content also 0 and set layout weight as 1(RCV is inside a linearlayout)
https://stackoverflow.com/a/44470106/6341943 => adding a header viewholder for some reason
https://stackoverflow.com/a/37558761/6341943 => cant do this because, I have a bottomnavbar
Now for the Weird part
If I keep my fragment inside a viewpager, for some reason the issue is not happening. (Even this hack is not usable is because it's messing up my collpsingToolbarLayout)
I have wasted at least a week behind this and the only solution that works is to remove the nestedscrollview. To make the recyclerview to actually recycle the view, you HAVE TO REMOVE the nestedscrollview. If you happen to have multiple views inside instead of just the recyclerview, You have to add them as items of the recyclerview by setting different viewholders, and then adding
app:layout_behavior="#string/appbar_scrolling_view_behavior"
to the recyclerview or the parent of recyclerview(the parent cannot have any other view other than Recyclerview for this to work).
In my case, the requirement was as follows:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:fitsSystemWindows="true"
app:layout_constraintTop_toTopOf="parent">
<!-- Scrollable view here -->
<com.google.android.material.appbar.AppBarLayout
.... >
<com.google.android.material.appbar.CollapsingToolbarLayout
....>
<androidx.appcompat.widget.Toolbar
....>
<include
android:id="#+id/toolbar_header_view"
.... />
</androidx.appcompat.widget.Toolbar>
<include layout="#layout/widget_header" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
....>
<LinearLayout orientation="vertical" ....>
<View .../> <!-- I needed to have these two views along with recyclerview and i wanted them to do nestedscroll along with recyclerview -->
<View .../>
<androidx.recyclerview.widget.RecyclerView
.... />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I needed to have two views before recyclerview and I wanted them to do nestedscroll along with recyclerview. The only thing that worked was by removing these to views and adding them as the first two items of recyclerview, and then adding
app:layout_behavior="#string/appbar_scrolling_view_behavior"
to the swipetorefresh layout
Hope this helps someone. I will add more info If required.

AndroidX Fragment recyclerview appearing over my toolbar and I need the recyclerview to scroll under the toolbar

I've created a AndroidX app using a main Activity with fragments. When I go to my fragment with the recyclerview the recycler view appears over the toolbar for the app. What I need is for the recyclerview to appear below the tool bar...
This is the main view with toolbar
This is the fragment with the recyclerview appearing over that toolbar :
Code for activity_mail.xml :
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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">
<LinearLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar"/>
<FrameLayout
android:id="#+id/fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/bottom_nav_view"
app:layout_constraintEnd_toEndOf="#id/toolbar"
app:layout_constraintStart_toStartOf="#id/toolbar"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar"/>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
app:itemBackground="#color/colorPrimaryDark"
app:itemTextColor="#drawable/nav_item_text"
app:itemIconTint="#drawable/nav_background"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/bottom_nav_menu"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
android:background="#002B49"
app:menu="#menu/drawer_view" />
</androidx.drawerlayout.widget.DrawerLayout>
EDIT Here is the layout for toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/products_toolbar"
android:layout_width="match_parent"
app:layout_scrollFlags="enterAlways"
android:background="#null"
android:layout_height="?attr/actionBarSize"
app:titleTextColor="#android:color/black"
local:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/rsi_logo"
android:layout_alignParentStart="true"/>
<ImageButton
android:id="#+id/toolbar_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/menu"
style="#style/Widget.AppCompat.Button.Borderless"
android:layout_alignParentEnd="true"
android:contentDescription="#string/menubutton"/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
As an added note this occurs on fragment's with scrollviews as well.
I tried to replicate your problem (created a repo), but I did not find the issue you specified.
Screenshot: Toolbar is shown
So I say that most probably the issue is with your view.RecyclerFragment code. It seems that you are hiding your the toolbar in your view.RecyclerFragment
It's better if you can share your view.RecyclerFragment code also.

Custom Toolbar view

I am looking a create a toolbar like whatsapp profile with co-ordinator layout.
But I am only able to show the main title on toolbar which has pinning property on action bar.
How can I add the sub title text and icon/custom view on the right , which has a similar pinning on actionbar property.
I have tried adding layout inside Toolbar tag in xml.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="400dp"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="#dimen/activity_horizontal_margin"
app:expandedTitleMarginStart="#dimen/activity_horizontal_margin"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="#+id/toolbar_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:contentDescription="#null"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="#drawable/beach_huts"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" >
<!-- adding views ,layouts here does not work -->
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
app:layout_scrollFlags="scroll" />
</android.support.design.widget.AppBarLayout>

Floating Toolbar with Appcompat

How to create a floating toolbar like the following image as proposed in the material design guidelines and in the Google Map application.
I've worked with the Toolbar before and all the comments from CommonsWare are absolutely correct.
The Toolbar widget (https://developer.android.com/reference/android/support/v7/widget/Toolbar.html) have absolutely nothing special or different than any other Viewgroup and does not behave differently than any other ViewGroup.
Put it inside a FrameLayout, put a layout_margin parameter on it, make the layout_width NOT match_parent and that's it.
Put it inside an LinearLayout with orientation=horizontal and you can use the layout_weight to control the size in percentage. Or just use plain dip if that suits your needs.
Since you are following the Material Design concept I am assuming your are using Coordinator Layout as your Main Layout and Not Frame Layout.
Before anything else we need to declare the important dependencies.
dependencies {
compile 'com.android.support:design:22.2.1'
compile 'com.android.support:cardview-v7:22.2.1'
}
Expected/Similar Output
XML snippet
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="#+id/frmlyout_locationnote_mapholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- You can add your Map here-->
<ImageView
android:id="#+id/imgvw_locationnote_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/tlbr_locationnote_mainmenu"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</android.support.v7.widget.CardView>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_locationnote_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_plus_white_24dp"
app:layout_anchor="#id/frmlyout_locationnote_mapholder"
app:layout_anchorGravity="bottom|right" />
</android.support.design.widget.CoordinatorLayout>
I think Mark's suggestion for picking up the CardView "look" in the comment above deserves this derivative answer:
Just put a Toolbar in a CardView:
<android.support.v7.widget.CardView
android:id="#+id/map_toolbar_container"
android:layout_width="#dimen/whatever_you_want"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardElevation="8dp"
app:cardBackgroundColor="#324">
<android.support.v7.widget.Toolbar
android:id="#+id/wld_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"/>
</android.support.v7.widget.CardView>
Just Add the following code....
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:id="#+id/toolbar"
android:background="#color/colorPrimary"
android:elevation="8dp"
android:layout_margin="5dp"
>
//add whatever elements you want to add in here.
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
**android:layout_margin="10dp"
android:elevation="5dp"**
/>
Here is the code for the floating toolbar, just copy and paste.
This is an example of a floating toolbar using Appcompat, It can be working under many layouts like Relative, Coordinator, or DrawerLayout. You can increase elevation to make it more effective.
floating toolbar with Edit text or Search box
<LinearLayout
android:background="#color/colorWhite"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<androidx.appcompat.widget.Toolbar
android:background="#drawable/floating_toolbar"
android:id="#+id/app_toolbar"
android:elevation="2dp"
android:layout_width="match_parent"
android:layout_height="50dp">
<EditText
android:gravity="start"
android:id="#+id/search_bar"
android:background="#drawable/edit_text_no_border"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Search here.." />
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
drawable/floating_toolbar.xml file for set background shadows.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="rectangle">
<solid android:color="#6FA5A5A5" />
<corners android:radius="6dp"/>
</shape>
</item>
<item android:top="1dp" android:right="1dp" android:left="1dp" android:bottom="1dp">
<shape
android:shape="rectangle">
<solid android:color="#color/colorWhite"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
drawable/edit_text_no_border.xml file for EditText without an outline box or bottom border to make it clean matching background.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffff"/>
<corners android:radius="0px"/>
<stroke android:width="0dp" android:color="#FFFFFF"/>
</shape>
Emoji = ThumbsUp

Add buttons above scroll (I guess you can't teach an old dog new tricks! )

ON SUNDAY I ACTUALLY SIDE-LOADED MY FIRST APP!!! Simple, unfinished, couple bugs, but it works.
My opening screen (XML: "event_list.xml") is a scroll list - select one get detail screen.
XML looks like: (This code is still a fragment.)
<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.dummies.android.taskreminder.EventListFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
And the row (XML "event_row.xml") looks like:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="12dp"
android:padding="2dip" />
I want a couple buttons at the top above the scroll. The best I can do is:
<?xml version="1.0" encoding="utf-8"?>
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.dummies.android.taskreminder.EventListFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button
android:id="#+id/btn_Add"
android:text="#string/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</fragment>
But the button overlays the first entry!
What ties the row to the list screen and how do I get two buttons above the scroll (rows)?
This is what finally worked.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="#+id/btn_Add"
android:layout_width="50dp"
android:layout_height="30dp"
android:textSize="12dp"
android:padding="1dip"
android:text="#string/add" />
<Button android:id="#+id/btn_Exit"
android:layout_width="50dp"
android:layout_height="30dp"
android:textSize="12dp"
android:padding="1dip"
android:layout_marginLeft="5dp"
android:layout_toRightOf="#+id/btn_Add"
android:text="#string/exit" />
<Button android:id="#+id/btn_Other"
android:layout_width="50dp"
android:layout_height="30dp"
android:textSize="12dp"
android:padding="1dip"
android:layout_marginLeft="5dp"
android:layout_toRightOf="#+id/btn_Exit"
android:text="#string/other" />
<fragment
android:name="com.dummies.android.taskreminder.EventListFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/btn_Add" />
</RelativeLayout>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="12dp"
android:padding="2dip" />
<!-- This defines a row in which text can be placed -->
<!-- "text1" is the IDof the view for loading the list with data -->
Now just need to make the button code copied from detail screen (activity only) work in list screen (w/ fragment):
This generates errors: (findViewById undefined)
mExitButton = (Button)findViewById(R.id.btn_Exit);
This crashed:
mExitButton = (Button)getView().findViewById(R.id.btn_Exit);
Still working in this (it's late):
View myFragmentView = inflater.inflate(R.layout.????????, container, false);

Resources