My app has an Activity with TabLayout, and 3 Fragments. In Activity's layout, I have CoordinatorLayout with ViewPager. I need to animate toolbar as well.
Now In Fragments layout, I need to put a fixed TextView at the bottom.
Given below is the XML of activity and fragment.
I am facing the problem that this fixed TextView in Fragment's
layout is going under the bottom navigation bar and is scrolling also,
that I don't want.
How can achieve this ?
activity.xml
<?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:id="#+id/clMain"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
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:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:textColor="#FFFFFF"
android:textSize="22sp"
android:textStyle="bold" />
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
fragment.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:background="#color/colorWhite"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:id="#+id/rlParent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:layout_weight="1"
android:fitsSystemWindows="true"
android:orientation="vertical">
</android.support.v4.widget.NestedScrollView>
<TextView
android:id="#+id/tvConfirmOrder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorDarkGreen"
android:gravity="center"
android:padding="10dp"
android:text="#string/confirm_order"
android:textColor="#color/colorWhite"
android:textSize="18sp"
android:textStyle="bold"></TextView>
</LinearLayout>
As you want this bottom fixed TextView for each fragment, it can be solved by transferring your TextView to activity.xml and adding a custom behavior to it.
So, firstly, create a class that represents custom behavior:
public class FixedBottomViewBehavior extends CoordinatorLayout.Behavior<View> {
public FixedBottomViewBehavior() {
}
public FixedBottomViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//making our bottom view depends on ViewPager (or whatever that have appbar_scrolling_view_behavior behavior)
return dependency instanceof ViewPager;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
if (ViewCompat.isLaidOut(parent)) {
//attach our bottom view to the bottom of CoordinatorLayout
child.setY(parent.getBottom() - child.getHeight());
//set bottom padding to the dependency view to prevent bottom view from covering it
dependency.setPadding(dependency.getPaddingLeft(), dependency.getPaddingTop(),
dependency.getPaddingRight(), child.getHeight());
}
return false;
}
}
There is no magic here, we're just making our bottom view dependent on some view with appbar_scrolling_view_behavior (in our case it's ViewPager) and then attaching it to the bottom of CoordinatorLayout and setting some padding to dependency.
Secondly, change your activity.xml, by adding your TextView there:
<?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/clMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
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:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:textColor="#FFFFFF"
android:textSize="22sp"
android:textStyle="bold" />
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<TextView
android:id="#+id/tvConfirmOrder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/colorDarkGreen"
android:gravity="center"
android:padding="10dp"
android:text="#string/confirm_order"
android:textColor="#color/colorWhite"
android:textSize="18sp"
android:textStyle="bold"
app:layout_behavior="your.package.name.FixedBottomViewBehavior" />
</android.support.design.widget.CoordinatorLayout>
Make sure you've removed your TextView from fragment.xml. Don't forget also to change your.package.name.FixedBottomViewBehavior to your package name exactly.
Voila! That should work like a charm with proper toolbar animation and fixed view at the bottom.
In addition: if you don't know how to pass your OnClick event to your fragments you can follow this way in your Activity:
public interface OnConfirmOrderClickListener {
void onConfirmOrderClick(View v);
}
public Fragment getActiveFragment() {
String name = makeFragmentName(pager.getId(), pager.getCurrentItem());
return getSupportFragmentManager().findFragmentByTag(name);
}
public String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
tvConfirmOrder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment current = getActiveFragment();
if (current instanceof OnConfirmOrderClickListener)
((OnConfirmOrderClickListener) current).onConfirmOrderClick(v);
}
});
Don't forget to make your fragments implements OnConfirmOrderClickListener. Hope that helps!
For those who want the button to appear only in one fragment, it's possible to use onPageChangeListener of ViewPager to make the button scroll with the ViewPager
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
updateButtonPosition(position, positionOffsetPixels);
}
});
//Move the button according to the tab you want it to be fixed.
//Here is the 3rd tab of a 3 tab viewPager, for instance
private void updateButtonPosition(int position, int positionOffsetPixels) {
int fixedRewardXPos;
if (position == 0) {
fixedRewardXPos = viewPager.getWidth() * 2 - positionOffsetPixels;
} else if (position == 1) {
fixedRewardXPos = viewPager.getWidth() - positionOffsetPixels;
} else {
fixedRewardXPos = -positionOffsetPixels;
}
//Add getLeft() to keep the button to its former position in it's fragment
aButton.setX(fixedRewardXPos + aButton.getLeft());
}
Related
i already check the xml file, but everything is okay (for me), but the view still stacked up. and i also get an error message like this
PlayingFragment: onResponse: hasil
pemanggilanretrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall#1c95dee5
and here's what inside on onResponse on my PlayingFramgment class
private void bacaData(){
progressBar.setVisibility(View.VISIBLE);
final RecyclerView rvCategory = getActivity().findViewById(R.id.playing_daftar);
rvCategory.setLayoutManager(new LinearLayoutManager(getActivity()));
ApiInterface apiInterface = ApiClient.getRetrofit(getContext()).create(ApiInterface.class);
Call<MovieResponse> call = apiInterface.getNowPlaying();
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
MovieResponse data = response.body();
if (data.getResults().size() == 0){
Toast.makeText(getContext(), "Maaf data yang anda cari tidak ditemukan",
Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
} else {
rvCategory.setAdapter(new MoviesAdapter(data.getResults(), R.layout.list_movie_row, getContext()));
Log.d(TAG, "onResponse: hasil pemanggil" + call);
progressBar.setVisibility(View.GONE);
}
}
#Override
public void onFailure(Call<MovieResponse> call, Throwable t) {
Toast.makeText(getContext(), "Gagal", Toast.LENGTH_SHORT).show();
Log.d(TAG, t.toString());
progressBar.setVisibility(View.GONE);
}
});
}
i post the xml layout fragment_playing
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragment.PlayingFragment">
<!-- TODO: Update blank fragment layout -->
<android.support.v7.widget.RecyclerView
android:id="#+id/playing_daftar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/progressMainBar"
android:layout_centerInParent="true"/>
</RelativeLayout>
fragment_playing is the part of fragment_home, and here's the code
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".BlankFragment">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
app:tabGravity="fill"
app:tabIndicatorColor="#color/colorAccent"
app:tabMode="fixed"
app:tabSelectedTextColor="#ffffff">
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/appbar"
android:padding="#dimen/activity_vertical_margin" />
</FrameLayout>
</LinearLayout>
and i put the fragment_home into content_main
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MainActivity"
tools:showIn="#layout/app_bar_main">
<android.support.v4.view.ViewPager
android:layout_below="#+id/toolbar"
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
content_main is the part of app_bar_main
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<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="wrap_content"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimaryDark"
app:tabTextColor="#color/colorAccent"
app:tabSelectedTextColor="#color/colorAccent"
android:id="#+id/tabs">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tab_np"
android:text="#string/now_playing"
android:textColor="#color/colorAccent"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/up_coming"
android:id="#+id/tab_up"/>
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</RelativeLayout>
You should use below property so your viewPager below your upper tab. I think your viewPager have height and width both are match parent.
Since you are using RelativeLayout as root component you have to give margin top to RecyclerView:
android:layout_marginTop="104dp"
EDIT:
if you were using coordinatorLayout as Root layout, the story would be different.
EDIT
Following issues are obvious in your codes:
1- AppBarLayout in Fragment home is extra since you have already an Appbar in activitie's home layout.
2- According to android official document use CoordinatorLayout instead of RelativeLayout. By using RelativeLayout you will loose some functionality and layout management of AppBarLayout
3- Since you have just included content_main inside app_bar_main, no needs to use tools:context=".MainActivity" and tools:showIn="#layout/app_bar_main"
4- Replace RelativeLayout inside content_main by merge tag
After above changes you have just removed extra layouts which may have side effects on margins and padings, then apply attribute below to your view pager. I hope these changes will be effective and no other hidden items are alive in your code:
android:layout_marginTop="104dp"
change you Relativelayout to android.support.design.widget.CoordinatorLayout and add app:layout_behavior="#string/appbar_scrolling_view_behavior" to android.support.v7.widget.RecyclerView
Use this for app_mar_main:
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/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="wrap_content"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimaryDark"
app:tabTextColor="#color/colorAccent"
app:tabSelectedTextColor="#color/colorAccent"
android:id="#+id/tabs">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tab_np"
android:text="#string/now_playing"
android:textColor="#color/colorAccent"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/up_coming"
android:id="#+id/tab_up"/>
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="#+id/appbarlayout"
android:layout_marginTop="1dp"/>
</RelativeLayout>
Try this way..
make viewpager xml code..
<?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:clickable="true"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/tab_bg_color"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/tlConversation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabIndicatorColor="#color/tab_color"
app:tabMinWidth="0dp"
app:tabMode="fixed"
app:tabTextAppearance="#style/Tab_Style"
app:tabSelectedTextColor="#color/tab_color"
app:tabTextColor="#color/tab_text_color">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/vpPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
</android.support.v4.view.ViewPager>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
after that fragement xml code for recyclerview ..
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tool="http://schemas.android.com/tools">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rvData"
tool:listitem="#layout/item_row_layout"
></android.support.v7.widget.RecyclerView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvEmpty"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tool:text="No data found"
android:text="#string/no_found"
android:visibility="gone"
/>
</android.support.constraint.ConstraintLayout>
after that setup view pager like this way make viewpager adapter..
private void setupViewPager(ViewPager viewPager) {
viewPagerAdapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager(),conversationId);
viewPager.setAdapter(viewPagerAdapter);
viewPager.setOffscreenPageLimit(1);
viewPager.setCurrentItem(currentItem);
}
And
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final Context context;
public ViewPagerAdapter(FragmentManager fragmentManager, Context context) {
super(fragmentManager);
this.context = context;
}
#Override
public Fragment getItem(int position) {
if(position == 0) return new ActiveConversationFragment();
if(position == 1) return new InvitedConversationFragment();
if(position == 2) return new RecentConversationFragment();
throw new IllegalStateException("Unexpected position " + position);
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
if(position == 0) return context.getString(R.string.tab_active_conversation_title);
if(position == 1) return getString(R.string.tab_invited_conversation_title);
if(position == 2) return getString(R.string.tab_recent_conversation_title);
throw new IllegalStateException("Unexpected position " + position);
}
}
after that call above method like this way set into tablayout..
setupViewPager(viewPager);
tabLayout.setupWithViewPager(viewPager);
I got some strange things happening when using CoordinatorLayout.Behavior with a FloatingActionButton.
Here is a snippet:
public class BottomFloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
public BottomFloatingActionButtonBehavior() {
}
public BottomFloatingActionButtonBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
return (dependency instanceof BottomNavigation);
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
if (dependency instanceof BottomNavigation) {
BottomNavigation bottomNavigation = (BottomNavigation) dependency;
int height = bottomNavigation.getNavigationHeight() - bottomNavigation.getBottomInset();
float offset = bottomNavigation.getTranslationY() - height;
child.setTranslationY(offset);
return true;
}
return false;
}
}
When using this behavior i get weird margins added to the button:
Then, when hiding the button and showing again (navigating between fragments) margins increase, but only once (do not get increased after each iteration):
This is my layout:
<?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=".Activities.MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/layout_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_main"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/frame_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<it.sephiroth.android.library.bottomnavigation.BottomNavigation
android:id="#+id/navigation_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_behavior="#string/bbn_appbar_behavior"
app:bbn_entries="#menu/activity_main_navigation" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/button_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
app:borderWidth="0dp"
app:fabSize="normal"
app:layout_behavior="it.sephiroth.android.library.bottomnavigation.BottomFloatingActionButtonBehavior"
app:srcCompat="#drawable/ic_fa_plus_white_24dp"
app:useCompatPadding="true"/>
</android.support.design.widget.CoordinatorLayout>
</layout>
What am i doing wrong? What is this behavior?
The most interesting is that if i change my super class to FloatingActionButton.Behavior then all margins are gone even after switching fragments (show/hide sequence):
But this class controls the snackbar by itself so it won't work for me.
This was tested using latest (and previous also) support lib: 25.2.0 on Nougat and KitKat versions. The difference is - on KitKat there is no "second shift phase". The margins show up from the start.
Try setting android:minWidth and android:minHeight to 0dp.
<android.support.design.widget.FloatingActionButton
android:minWidth="0dp"
android:minHeight="0dp"
android:id="#+id/button_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
app:borderWidth="0dp"
app:fabSize="normal"
app:layout_behavior="it.sephiroth.android.library.bottomnavigation.BottomFloatingActionButtonBehavior"
app:srcCompat="#drawable/ic_fa_plus_white_24dp"
app:useCompatPadding="true"/>
in my app I am using a viewpager with 3 fragments. In two of those I have recuclerviews. I took advatngage of the new Coordinator layout and made my toolbar hides/shows when scrolling on a recyclerview. My problem is the following Say the user is scrolling on a recyclerview list in fragment A and thus the toolbar is hidden. After that, the user performs a swipe and goes to fragment B which does not have a recycle view to scroll so the toolbar can appear again. Is there a way I can alter the layout_behaviout so that when the user swipes on the view pager the toolbar to be shown?
NOTE: IF it is possible, I want to achieve that only using XML.
This is my main_layput xml code:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="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="com.studentsins.lust.MainActivity">
<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"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/NavigationTab"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<include layout="#layout/content_main"/>
<com.getbase.floatingactionbutton.FloatingActionsMenu
android:id="#+id/floatingActionMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
fab:fab_addButtonColorNormal="#color/blood_orange"
fab:fab_addButtonColorPressed="#color/dirtyWhite"
fab:fab_addButtonPlusIconColor="#color/dirtyWhite"
fab:fab_addButtonSize = "normal"
fab:fab_labelStyle="#style/menu_labels_style"
fab:fab_labelsPosition="left"
app:layout_anchor="#id/viewpager"
app:layout_anchorGravity="bottom|end">
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="#+id/createPlanBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_colorNormal="#color/blood_orange"
fab:fab_title="Create a plan"
fab:fab_size="normal"
app:fab_icon="#drawable/ic_event_white_48dp"
fab:fab_colorPressed="#color/dirtyWhite"/>
<com.getbase.floatingactionbutton.FloatingActionButton
android:id="#+id/changeStatusBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_colorNormal="#color/blood_orange"
fab:fab_size="normal"
app:fab_icon="#drawable/ic_textsms_white_48dp"
fab:fab_title="Change status"
fab:fab_colorPressed="#color/dirtyWhite"/>
</com.getbase.floatingactionbutton.FloatingActionsMenu>
</android.support.design.widget.CoordinatorLayout>
You should be able to do this using the ViewPager.OnPageChangedListener and based on the page u are on which u can get from the onPageSelected(int position) method that is part of the listener. Hope this is what u are looking for.
I was able to achieve this by referencing the AppBarLayout and calling the "setExtended" method like that:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Make sure that the fab is visible when scrolling the pages...
MainActivity.mFloatingActionsMenu.animate()
.setDuration(150)
.translationY(0);
//show the toolbar
expandToolbar();
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
my expandToolbar method:
public void expandToolbar(){
//setExpanded(boolean expanded, boolean animate)
AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.appBarLayouy);
appBarLayout.setExpanded(true, true);
}
I'm trying to get a Floating Action Button from the Android Design Support Library inside a Fragment which is inside a ViewPager. I've 4 tabs and I want the FAB in only one of the Tabs. My layout are as follows:
main_layout.xml
<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/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<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/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
app:tabIndicatorHeight="3dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
list_fragment_with_fab.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="5dip"
android:background="#color/Transparent_White"
android:fitsSystemWindows="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.lucasr.twowayview.widget.TwoWayView
android:id="#+id/clip_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:twowayview_layoutManager="ListLayoutManager" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/add_list_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#drawable/ic_list_add"
app:layout_anchor="#+id/clip_recycler_view"
app:layout_anchorGravity="bottom|right|end" />
Now the problem is, the FAB does not work as per the design specs. i.e the hiding and showing of the fab doesn't work. Also, the FAB is not at it's initial place when the fragment is activated. I've attached screenshots below to make it more clear.
The in the left image, as you can see, the FAB is off the screen. When I scroll, the Toolbar will hide (think Play Store App) and the tabs remain, that time the FAB will scroll up.
Is this a bug in the Design Support library? Or is my layout incorrect? Also, I want the FAB in only one of the fragments, so adding in the main_layout.xml kinda defeats that purpose.
It's not strictly a bug, but just the way they've implemented it.
It's because of this:
app:layout_behavior="#string/appbar_scrolling_view_behavior"
This behavior doesn't manipulate the size of the ViewPager, it just pushes it off the bottom of the screen when the AppBarLayout is expanded.
Your fragment is filling the entire size of the ViewPager and so correctly aligns the FAB to the bottom right of the ViewPager container; but because the ViewPager container is offset, the bottom right is offscreen.
The "proper" way of using a FloatingActionButton in this context is by having the activity show it - like this:
<?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:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="bubblebearapps.co.uk.nfcapi.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
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:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
You then change the FloatingActionButton's size, icon and onClickBehaviour based on what page is shown in the ViewPager using the OnPageChangeListener interface.
To make the FloatingActionButton scroll off the bottom when you're scolling the RecyclerView, you must create a Behaviour! This is one I used in a different project:
public class ScrollOffBottomBehaviour extends CoordinatorLayout.Behavior<View> {
private int mViewHeight;
private ObjectAnimator mAnimator;
public ScrollOffBottomBehaviour(Context context, AttributeSet attrs) {
super();
}
#Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
mViewHeight = child.getHeight();
return super.onLayoutChild(parent, child, layoutDirection);
}
#Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child,
View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if(mAnimator == null || !mAnimator.isRunning()){
int totalScroll = (dyConsumed + dyUnconsumed);
int targetTranslation = totalScroll > 0 ? mViewHeight : 0;
mAnimator = ObjectAnimator.ofFloat(child, "translationY", targetTranslation);
mAnimator.start();
}
}
#Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
}
Set this onto your FloatingActionButton with app:layout_behaviour and all should be well...
I am trying to achieve the following affect (also see image below):
the app opens with a view (map) partially visible and the RecyclerView at a default anchor point (center image)
user scrolls the RecyclerView up, the map collapses and the list continues scrolling (right image)
user scrolls the RecyclerView down, the map expands to a maximum point (note the list should not slide completely off screen but to some anchored point) (left image)
To create this we need 1 Activity and 3 Fragments.
The Activity will host a TabLayout and a ViewPager like so:
<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">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Since we only need to do the sliding behavior for the 1st Fragment the first Fragment gets an XML layout like so:
<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.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="400dp"
android:orientation="vertical"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
app:layout_collapseMode="parallax"
android:layout_height="400dp"
android:layout_width="match_parent" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
You can make the other Fragments however you like I just created fake data and a simple RecyclerView in the other Fragments.
Then call these views in your Activity and Fragment like so:
Activity
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
private SampleViewPagerAdapter mViewPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.another_activity);
mTabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPagerAdapter = new SampleViewPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mViewPagerAdapter);
mTabLayout.setupWithViewPager(mViewPager);
}
}
ViewPager Adapter
public class SampleViewPagerAdapter extends FragmentPagerAdapter {
public SampleViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new MapFragment();
case 1:
return new ScrollFragment();
case 2:
return new ScrollFragment();
default:
return new ScrollFragment();
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
String[] tabNames = {"Stops", "Planner", "Alerts"};
return tabNames[position];
}
}
Map Fragment with Sliding RecyclerView
public class MapFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.activity_main, null);
initCollapsingToolbar(root);
// Initialize map
initFragment();
return root;
}
private void initCollapsingToolbar(View root) {
CollapsingToolbarLayout collapsingToolbarLayout =
(CollapsingToolbarLayout) root.findViewById(R.id.collapsingToolbar);
collapsingToolbarLayout.setContentScrimColor(getResources().getColor(R.color.cyan_500));
}
private void initFragment() {
FakeDataFragment fragment = new FakeDataFragment();
getChildFragmentManager().beginTransaction()
.replace(R.id.content, scrollFragment)
.commit();
}
}
You should get something like this then:
Setting the position:
You can programmatically collapse the toolbar (CollapsingToolbarLayout) using the following code:
public void collapseToolbar(){
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) mFrameLayout.getLayoutParams();
AppBarLayout.ScrollingViewBehavior behavior = (AppBarLayout.ScrollingViewBehavior) params.getBehavior();
if (behavior != null) {
behavior.onNestedFling(rootLayout, appbarLayout, null, 0, 10000, true);
}
}
This means when the User first sees the map the map is partially collapsed to your Default State.
I Found Solution for Tabs in CoordinatorLayout
<?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/htab_maincontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/htab_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:id="#+id/htab_collapse_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:statusBarScrim="#null"
app:titleEnabled="false">
<LinearLayout
android:id="#+id/isprofile"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#drawable/profile_cover"
android:gravity="center"
app:layout_collapseMode="parallax">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="vertical">
<com.root.findagame.utills.CircleImageView
android:id="#+id/profile_pic"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#drawable/profile_pic" />
<TextView
android:id="#+id/txtUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="#color/cpb_white"
android:textSize="#dimen/text_medium_size"
android:textStyle="bold" />
<TextView
android:id="#+id/txtAge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text=""
android:textColor="#color/cpb_white"
android:textSize="#dimen/text_small_size" />
<TextView
android:id="#+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text=""
android:textColor="#color/cpb_white"
android:textSize="#dimen/text_small_size"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
<android.support.v7.widget.Toolbar
android:id="#+id/htab_toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:visibility="gone"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.design.widget.TabLayout
android:id="#+id/htab_tabs"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:background="#color/cpb_white"
app:layout_collapseMode="pin"
app:tabIndicatorColor="#7CC142"
app:tabSelectedTextColor="#7CC142"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabTextAppearance="#android:style/TextAppearance.Widget.TabWidget"
app:tabTextColor="#color/lightGrayColor" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/htab_viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
*Fragment*
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/dummyfrag_bg"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/dummyfrag_scrollableview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</FrameLayout>