Where to add toolbar and navigation bar - android

I'm using android navigation controller.
My main activity hosts a nav fragment but where should other components like toolbars and nav bottom bar go, in the main activity or child fragments?
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</LinearLayout>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</RelativeLayout>
or should ToolBar and BottomNavigationView be in fragment_home.xml like so
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</RelativeLayout>

I'll supply you with an example. Keep in mind, I'm compiling with the latest androidx for SDK 28+ so if you are on older, your namespaces will be slightly different.
I'm also using Databinding and Kotlin, so don't use the layout and data tags if you are not using databinding.
TOOLBAR
<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">
<data>
PUT BINDING VARIABLES HERE
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/SSTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:theme="#style/ToolbarTextAppearance">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MAIN ACTIVITY
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable name="activity" type="com.a35.activities.MainActivity"/>
<variable name="iBindingRecyclerView" type="com.a35.interfaces.IBindingRecyclerView"/>
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--TOP TOOLBAR-->
<include
android:id="#+id/toolbarMain"
layout="#layout/toolbar_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<!--TOP BLACK LINE-->
<View
android:id="#+id/vRedLine"
android:layout_width="match_parent"
android:layout_height="#dimen/dp_2"
android:background="#color/black" />
<!-- FrameLayout is used to insert fragments to display -->
<FrameLayout
android:id="#+id/fragPlaceholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="#color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/nav_drawer_header"
android:id="#+id/navHeader"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/lstMenuItems"
android:layout_below="#+id/navHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bindRcvInterface="#{iBindingRecyclerView}"
app:bindRcvList="#{activity.getDrawerItemList}"/>
<ImageView
android:id="#+id/imgBottomLogo"
android:layout_width="#dimen/dp_160"
android:layout_height="#dimen/dp_35"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="#dimen/dp_35"
android:src="#drawable/scott_logo" />
</RelativeLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>
Notice the Main Activity holds Navigation View that is inside a drawer layout which contains the Recycler View for building your drawer content.
Outside of that you will see the content placeholder for fragments called fragPlaceHolder.
Lastly notice the parent layout is a LinearLayout with the first element being the include for the toolbar to include as we see fit.
Next your Styles. You'll need to use a style that does not rely on the action bar if you plan to use the toolbar as the actionbar. (for the record, you should be using the toolbar)
STYLE
<!--Full Screen-->
<style name="A35.FullScreen">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
MANIFEST
<application
android:name=".application.A35Application"
android:allowBackup="true"
android:icon="#mipmap/a35_logo"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/A35.FullScreen">
You can also put it on individual Activities if that fits your need better.
Now you have two steps left.
You need to call setActionToolbar and pass your found UI or use synthetic views if you are using kotlin and databinding that is simple to do. So add in your onCreate AFTER inflating the view.
setSupportActionBar(toolbar)
You didn't ask this, but I'll supply it as well. When you need to change out your fragment, I typically have a BaseActivity with a helper method that does it like so.
protected fun swapFragment(fragment: BaseFragment, #Nullable bundle: Bundle?, hideCurrentFrag: Boolean = false) {
if (fragment.isVisible) {
A35Log.e(mClassTag, "swapFragment called on already visible fragment")
return
}
A35Log.v(mClassTag, "swapFragment( ${fragment.javaClass.simpleName} )")
val currentFragBundle = fragment.arguments
if (currentFragBundle == null && bundle != null) {
fragment.arguments = bundle
A35Log.v(mClassTag, "current bundle is null, so setting new bundle passed in")
} else if (bundle != null) {
fragment.arguments?.putAll(bundle)
A35Log.v(mClassTag, "current fragment bundle was not null, so add new bundle to it")
}
val fragmentManager = supportFragmentManager
fragmentManager.executePendingTransactions()
val fragmentTransaction = fragmentManager.beginTransaction()
//Make sure the requested fragment isn't already on the screen before adding it
if (fragment.isAdded) {
A35Log.v(mClassTag, "Fragment is already added")
if (fragment.isHidden) {
A35Log.v(mClassTag, "Fragment is hidden, so show it")
fragmentTransaction.show(fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}else{
A35Log.v(mClassTag, "Fragment is already visible")
}
}else if(mSelectedFragment == null){
A35Log.v(mClassTag,"mSelectedFragment = null, so replacing active fragment with new one ${fragment.javaClass.simpleName}")
fragmentTransaction.replace(R.id.fragPlaceholder, fragment)
}else{
A35Log.v(mClassTag, "Fragment is not added, so adding to the screen ${fragment.javaClass.simpleName}")
fragmentTransaction.add(R.id.fragPlaceholder, fragment)
if(hideCurrentFrag) {
A35Log.v(mClassTag, "hideCurrentFlag = true, hiding current fragment $mSelectedFragment")
fragmentTransaction.hide(mSelectedFragment!!)
}else{
A35Log.v(mClassTag, "hideCurrentFlag = false, removing current fragment $mSelectedFragment")
fragmentTransaction.remove(mSelectedFragment!!)
}
}
A35Log.v(mClassTag, "committing swap fragment transaction")
fragmentTransaction.commit()
A35Log.v(mClassTag, "mSelectedFragment = ${fragment.javaClass.simpleName}")
mSelectedFragment = fragment
}
NOTE* While swapping fragments is fairly universal, you need to make sure you are handling your needs properly. Should it be hiding, or removing. Should it be handling the bundles or ignoring them. The method I supplied you is basically showing if non-existent and hiding fragment instead of removing if told to hide it.
Handling building an adapter and list for the nav drawer and wiring up listener clicks on those items is not shown here as that was not your question and is beyond the scope of this question. I don't want to make my answer too bloated, so hopefully that is all you need to get going.
Happy Coding.

Related

Multiple Toolbar layouts for different fragments

I have adopted the "one activity, multiple fragments" way of defining layouts for my Android (Xamarin) application. All views (fragments) share the same BottomNavigationView managed by MainActivity that adds each fragment to the same FrameLayout. But, as some fragments need to define their own AppBarLayouts, to for example create a CollapsingToolbarLayout, I can not just create a FragmentTransaction and put those fragments in the same FrameLayout container, as the Toolbar is part of the Activity's layout and thus not managed by the fragments. It would also seem counterproductive having to add and manage a Toolbar for each Fragment.
What I have tried so far:
Having a FrameLayout for each variation and then show/hide
accordingly (in layout for MainActivity) when making a
FragmentTransaction.
Use a fullscreen DialogFragment to show contents
above the active fragment.
Convert the "offending" fragment into an
Activity (makes it hard to handle the BottomNavigationView).
MainActivity currently looks like this (with some details omitted):
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<include
android:id="#+id/appbar_main"
layout="#layout/toolbar_main"/>
<FrameLayout
android:id="#+id/fragment_container"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<include
android:id="#+id/bottombar"
layout="#layout/toolbar_nav" />
</android.support.design.widget.CoordinatorLayout>
appbar_main layout (used by MainActivity)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<!-- logo layout -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:orientation="horizontal"
android:layout_gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
appbar_collapsing layout (for example used to show a profile page)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="#drawable/toolbar_app_bg"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ffimageloading.views.ImageViewAsync
android:id="#+id/imageViewCover"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.9" />
<ffimageloading.views.ImageViewAsync
android:id="#+id/imageViewProfile"
android:layout_width="100dp"
android:layout_height="100dp"/>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
The appbar_main layout provided above is quite simple and also the primary way of showing the Toolbar. appbar_collapsing differs from the main layout in that the Toolbar is nested within a CollapsingToolbarLayout to make it collapsible when scrolling while also collapsing two ImageView.
Any examples and advaree is much appreciated!
In fragments with bottom layout with changing needs for toolbars.
After testing different methods i concluded with this:
private void createMenus(Toolbar actionBarToolBar, #MenuRes int menu){
((MainActivity) Objects.requireNonNull(getActivity())).setSupportActionBar(actionBarToolBar);
actionBarToolBar.setTitle("");
actionBarToolBar.inflateMenu(menu);
}
Call this method here:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mRootView = inflater.inflate(R.layout.fragment_profile, container, false);
createMenus(mToolbar,R.menu.profile_menu);
setHasOptionsMenu(true);
//add fragments to adapter
//...
return mRootView;
}
Then override this:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.profile_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}

Contents of my main activity over Laps my fragments [duplicate]

I have the following XML:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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>
<!--I use this include as container with the FrameLayout below-->
<!--<include layout="#layout/content_main" />-->
<FrameLayout
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/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.improvemybrand.MainActivity"
tools:showIn="#layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</FrameLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_input_add" />
and the problem is simple:
When I try to replace the container FrameLayout from my Coordinator, it does not work, it shows the new fragment but also keeps the old one, in my simple example, the TextView with Hello world will remains.
To replace, I'm using the following code:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_main, fragment);
transaction.commit();
Any ideas?
FragmentTransactions deal only with Fragments and their Views. The TextView you've defined in your layout is not (part of) a Fragment's View, so it will not be affected by a FragmentTransaction, and the Fragment in your snippet will just be added on top of it.
You have a few options. You could hide or remove the TextView yourself when performing the transaction. This might be preferable, if that simple TextView is all you need initially, and sticking it in a Fragment could be overkill. You could also simply set an opaque background on the Fragment's layout, which will effectively hide the TextView.
The probably best option, however, is to put the TextView in a layout for another Fragment which is loaded at startup. Subsequent transactions will then replace/remove it as you're expecting. Do note that any Fragment you wish to replace/remove at runtime must be loaded dynamically in your code. That is, they cannot be defined in <fragment> elements in your Activity's layout.
You should move TextView into Fragment's layout.
like this.
fragment_hello_world.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
</LinearLayout>
HelloWorldFragment
public class HelloWorldFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_hello_world, container, false);;
}
}

android: Replace fragment container inside a CoordinatorLayout

I have the following XML:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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>
<!--I use this include as container with the FrameLayout below-->
<!--<include layout="#layout/content_main" />-->
<FrameLayout
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/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.improvemybrand.MainActivity"
tools:showIn="#layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</FrameLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_input_add" />
and the problem is simple:
When I try to replace the container FrameLayout from my Coordinator, it does not work, it shows the new fragment but also keeps the old one, in my simple example, the TextView with Hello world will remains.
To replace, I'm using the following code:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_main, fragment);
transaction.commit();
Any ideas?
FragmentTransactions deal only with Fragments and their Views. The TextView you've defined in your layout is not (part of) a Fragment's View, so it will not be affected by a FragmentTransaction, and the Fragment in your snippet will just be added on top of it.
You have a few options. You could hide or remove the TextView yourself when performing the transaction. This might be preferable, if that simple TextView is all you need initially, and sticking it in a Fragment could be overkill. You could also simply set an opaque background on the Fragment's layout, which will effectively hide the TextView.
The probably best option, however, is to put the TextView in a layout for another Fragment which is loaded at startup. Subsequent transactions will then replace/remove it as you're expecting. Do note that any Fragment you wish to replace/remove at runtime must be loaded dynamically in your code. That is, they cannot be defined in <fragment> elements in your Activity's layout.
You should move TextView into Fragment's layout.
like this.
fragment_hello_world.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
</LinearLayout>
HelloWorldFragment
public class HelloWorldFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_hello_world, container, false);;
}
}

Calling a fragment on top of viewpager overlaps each other

I have the following layout
<?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:id="#+id/coordinator_bracket_activity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/activity_fragment"
android:layout_height="match_parent"
android:layout_width="match_parent">
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/app_bar_bracket_activity"
layout="#layout/app_bar" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foregroundTint="#color/colorAccent"
app:tabMode="fixed"
app:tabMaxWidth="0dp"
app:tabGravity="fill"/>
<mypackage.NonSwipeViewPager
android:id="#+id/tabs_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
The nonswipeviewpager was just a custom class where I inherited a viewpager to disable some stuff.
Anyway, I have a button on my app bar that needs to call a fragment that needs to cover the whole screen. I would call it and add a fragment on the frame layout. It worked before I added a viewpager for tab layouts. Now I'm not sure how to deal with the viewpager.
FragmentTransaction ft = mFM.beginTransaction();
mCustomFragment = CustomFragment.newInstance(mObject, mListOfObjects());
ft.replace(R.id.activity_fragment, mCustomFragment , "CustomFragment");
ft.addToBackStack(null);
ft.commit();
This is on my clicklistener of that button on the app bar.
Thoughts?
Views are drawn in the order they are defined in your XML. If you want a View on top of another view it should appear after it or you try to use:
https://developer.android.com/reference/android/view/View.html#bringToFront()

Floating action button will not disappear when going to another fragment

I built a project based on Scrolling Activity, and faced a strange issue. Consider the following scenario:
I click on fab button to go to another fragment but when the fragment displaces, the fab button will not disappear!
Can anybody know how to fix this problem?
Here is my XML of Scrolling Activity that I added to my frameLayout:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="ir.apio.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="#dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<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/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_scrolling" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_dialog_email"
app:layout_anchor="#id/app_bar"
app:layout_anchorGravity="bottom|end" />
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
content_scrolling.xml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="ir.apio.myapplication.ScrollingActivity"
tools:showIn="#layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:text="#string/large_text" />
</android.support.v4.widget.NestedScrollView>
My fab ClickListener :
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame,new TestFragment())
.commit();
}
});
And also my TestFragment :
public static class TestFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test,container,false);
return view;
}
}
Here is the screen-shot in the first place:
Here is screen-shot when going to the new fragment:
The reason you are still seeing the FAB is elevation, which refers to a views depth on the screen. It affects which elements are above or below one another and the shadows they cast(for example a FAB sits on top of the main content and casts a shadow).
The FAB by default will have some elevation, which you can override using the elevation attribute, eg app:elevation="4dp". The other elements will be at the 0dp level.
In your case, you've put the FrameLayout last in your layout file, and I presume that's where you are loading your fragment into. What this does is not actually replace your other content, but just cover it with the content of your FrameLayout.
The reason it doesn't cover the FAB, is because the FAB has some elevation and the FrameLayout doesn't. So although you've put your FrameLayout last and would normally expect that to be "on top", the FAB actually has a higher elevation which overrides that.
A quick fix, would be to give your floating action button app:elevation=0dp which would put it back on the same elevation level as everything else and the normal rules would apply, the FrameLayout is last and would be on top.
In reality, just putting a big frame covering the previous content is not usually the best thing to do and you would want to look at other ways to structure the app.
I had the same problem. I called the .hide() method on the FragmentTransaction and it worked for me.
fab.setOnClickListener {
val fragmentManager = fragmentManager
val fragmentTransaction = fragmentManager?.beginTransaction()
val fragment = YourFragment()
fragmentTransaction?.add(R.id.fragment_container, fragment)
fragmentTransaction?.addToBackStack(null)
fragmentTransaction?.hide(this)
fragmentTransaction?.commit()
}

Categories

Resources