I have a view that fill my screen, i'm animating its Y so the top of it going hidden, BUT i need it's button keep it's position.
the animation code:
mainLayout.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();
Before Scrolling:
After Scrolling:
NOTE:
1) i'm doing this because i need to hide toolbar on scroll.
2) i tried other method for hiding toolbar include animating toolbar height, margin, padding, BUT they are laggy as hell.
3) i tried to translate the toolbar but it's below layout keep their position and won't move up.
UPDATE 1:
<android.support.v4.widget.DrawerLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/home_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context=".HomeActivity"
android:cacheColorHint="#android:color/transparent"
android:clipToPadding="false"
>
<!-- main view -->
<RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/tansparent"
android:id="#+id/home_main_layout"
tools:context=".HomeActivity">
<android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/home_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/category_activity_topbar_background"
app:theme="#style/Theme.AppCompat"
android:layout_alignParentTop="true"/>
<com.viewpagerindicator.TabPageIndicator
android:id="#+id/tab_indicator"
android:layout_height="#dimen/tab_height"
android:layout_width="match_parent"
android:layout_below="#+id/home_toolbar"/>
<android.support.v4.view.ViewPager
android:id="#+id/home_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tab_indicator"/>
<ImageButton
android:id="#+id/addBookButton"
android:layout_width="#dimen/add_button_width_height"
android:layout_height="#dimen/add_button_width_height"
android:scaleType="centerInside"
android:src="#drawable/add_button"
android:background="#drawable/circles_background"
android:adjustViewBounds="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="#dimen/add_button_margin_bottom"
android:layout_marginRight="#dimen/add_button_margin_right"
android:onClick="importNewBooksButtonMethod"/>
</RelativeLayout>
<!-- drawer -->
<LinearLayout
android:id="#+id/settingDrawer"
android:layout_width="#dimen/setting_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical"
android:background="#color/white"
android:clickable="true">
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
ok, i animated the whole view and after that i set margin for the view to a negative value. toolbar getting hide and everything works smooth an fine.
homeMainLayout.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).withEndAction(new Runnable()
{
#Override
public void run()
{
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) homeMainLayout.getLayoutParams();
params.bottomMargin = -toolbarHeight;
homeMainLayout.setLayoutParams(params);
}
}).start();
Related
I want to achieve the following behavior -
https://ezgif.com/optimize/ezgif-6-66c61806b01c.gif
here he is my XML file -
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_marketplace_root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="7dp">
<LinearLayout
android:id="#+id/fragment_marketplace_main_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:orientation="vertical">
<com.twoverte.views.ClearableAutoCompleteTextView
android:id="#+id/fragment_marketplace_searchview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="14dp"
android:completionThreshold="0"
android:hint="#string/fragment_marketplace_search_hint"
android:iconifiedByDefault="false"
android:inputType="text|textAutoCorrect"
android:maxLength="25"
android:textIsSelectable="false"
android:textSelectHandle="#xml/empty_shape"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="1dp" />
<TextView
android:id="#+id/fragment_marketplace_discover_products_from_myverte_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="15dp"
android:fontFamily="#font/noto_sans"
android:text="#string/fragment_marketplace_discover_products_from_myverte"
android:textSize="17sp" />
<androidx.core.widget.NestedScrollView
android:id="#+id/fragment_marketplace_vendors_nested_scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_marketplace_vendors_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:orientation="horizontal"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/fragment_marketplace_vendor_row_item" />
</androidx.core.widget.NestedScrollView>
<androidx.core.widget.NestedScrollView
android:id="#+id/fragment_marketplace_featured_products_nested_scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/fragment_marketplace_featured_products_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/very_light_grey"
android:fontFamily="#font/noto_sans"
android:paddingStart="14dp"
android:paddingLeft="14dp"
android:paddingTop="15dp"
android:paddingEnd="14dp"
android:text="#string/fragment_marketplace_featured_products"
android:textSize="17sp"
android:visibility="gone"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_marketplace_products_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#color/very_light_grey"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:listitem="#layout/fragment_marketplace_products_row_item" />
<View
android:id="#+id/activity_product_page_bottom_view"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="60dp"
android:background="#color/light_black"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I have tried SO MANY combinations with setOnScrollChangeListener and addOnScrollListener and nothing works as expected.
The needed result is to have the ability to increase and decrease the top RV up to a cap.
The decrease should be done when scrolling the bottom RV downwards while the increase is being done when scrolling up.
If someone can assist me with this I would literally kiss his legs, I have been investing so many hours trying to crack how to make this behavior that I am sick of it.
edit
the needed animation -
I finally figured it out. I will share the code for the XML file as it is first, then explain everything about it later.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:minHeight="132dp"
android:fitsSystemWindows="true"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<View
android:id="#+id/blue_view"
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="#android:color/holo_blue_bright"
app:layout_collapseMode="pin"
app:layout_collapseParallaxMultiplier="0"
android:layout_gravity="top"/>
<HorizontalScrollView
android:id="#+id/pink_view"
android:layout_width="match_parent"
android:layout_height="128dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="1"
android:layout_gravity="bottom">
<View
android:layout_width="2000dp"
android:minWidth="2000dp"
android:layout_height="match_parent"
android:background="#color/colorAccent"/>
</HorizontalScrollView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note: I used View with different colors in order to preview different segments in the Layout. I also used HorizontalScrollView in order to showcase something like a RecyclerView as in the gif you uploaded.
Alright, so first, we need to create a CollapsingToolbarLayout with layout_scrollFlags.
we use scroll flag must be enabled for any scroll effects to take into effect
we use snap flag to determine what to do when a view only has been partially reduced. If scrolling ends and the view size has been reduced to less than 50% of its original, then this view to return to its original size. If the size is greater than 50% of its sized, it will disappear completely.
we use exitUntilCollapsed along with minHeight in order to collapse the Toolbar down to the specified minHeight
We want the CollapsingToolbarLayout to have:
layout_height set to the expanded height of the Toolbar
minHeight set to the collapsed height of the Toolbar
In this case, since we want the HorizontalScrollView (pink_view) only to get smaller in height, we set the minHeight to the [ height of blue_view + smaller height of pink_view ]
Therefore, since blue_view will remain 128dp and we want pink_view to go down to 4dp, we set the minHeight to 132dp.
So here is a small example. Assume the blue_view is like 100dp and the pink_view is initially 100dp. So that's how we want it to show at first, but when I start scrolling we want the pink_view to go down to 20dp and the blue_view will stay at 100dp.
Therefore, layout_height will be 200dp and the minHeight will be 120dp.
Now, we want the HorizontalScrollView or the pink_view to collapse with the CollapsingToolbarLayout height.
So, we add layout_collapseMode="parallax" to the pink_view such that it scrolls along with the CollapsingToolbarLayout.
The layout_collapseParallaxMultiplier determines what part of the image (in percent) will be hidden under the bottom content. And here, we want it all to be hidden. Therefore, we set it to 1.
Meanwhile, we want the blue_view to stay pinned to the top. And we also don't want it to be hidden under any bottom content.
So, we add layout_collapseMode="pin" to the blue_view such that it gets pinned to the top of the CollapsingToolbarLayout.
We also add layout_collapseParallaxMultiplier="0" in order to not have it be hidden under any content.
Please note that if the heights of the elements exceeds the minHeight, the CollapsingToolbarLayout will be pushed above the screen. It will then seem as if the height of the top item (here blue_view) is decreasing in size.
Preview:
Here is another demo with a RecyclerView:
The XML for the above RecyclerView demo is below if anyone is interested.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:minHeight="148dp"
android:fitsSystemWindows="true"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<View
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="#android:color/holo_blue_bright"
app:layout_collapseMode="pin"
app:layout_collapseParallaxMultiplier="0"
android:layout_gravity="top"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/hv_list"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="128dp"
android:minHeight="20dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="1"
android:layout_gravity="bottom"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Edit : Important thing for RecyclerViews and ViewHolders
To achieve the height resize for RecyclerView and ViewHolder, we have to resize them when the offset of the AppBarLayout changes on scroll.
This is because the CollapsingToolbarLayout just scrolls the elements inside it under each other instead of actually resizing them.
So, we have to use the RecyclerView, called here hv_list, and the AppBarLayout, called here app_bar.
val hv_list: RecyclerView = findViewById(R.id.hv_list)
val app_bar: AppBarLayout = findViewById(R.id.app_bar)
After that, we need to remember the original size of the hv_list.
val hv_original_height: Int = hv_list.layoutParams.height
Finally, we need to set an OffsetChangedListener for the AppBarLayout. There, we will be changing the height of the RecyclerView and then give it a margin bottom to push it up only because it has a gravity bottom.
app_bar.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int) {
hv_list.updateLayoutParams {
this.height = hv_original_height + i
(this as CollapsingToolbarLayout.LayoutParams).setMargins(0, 0, 0, abs(i))
}
}
})
Make sure that your itemView in the RecyclerView has height of match_parent
What I'm trying to implement is a Toolbar that is not full width (has a margin on all sides of 16dp) like the following:
Gmail - Please note that the RecyclerView can be seen scrolling behind the toolbar
Google App - Same thing, the cards can be seen behind the toolbar.
Additionally, these toolbars hide when scrolling down and appear when scrolling up.
The content of the toolbar is not what I'm worried about right now.
I'm assuming this is done using a Coordinator Layout so this is the skeleton I have:
Coordinator Layout
AppBarLayout
Toolbar
NestedScrollView (appbar_scrolling_view_behavior)
ConstraintLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context=".MainContentFragment">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_margin="32dp"
android:background="#android:color/transparent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/holo_red_dark"
app:layout_scrollFlags="scroll|enterAlways">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
...
This is the output before scrolling
And after scrolling down
As you can see the space outside the toolbar is not transparent but has that grey background, since the content is going under it and cannot be seen.
The idea behind showing the content behind the toolbar:
Setting a negative margin to the scrolling view (NestedScrollView/RecyclerView) which equals to what you want the size of the blank area when all the content are scrolled up (all the stuff below the toolbar, nothing behind); it's assumed -100dp in the below demo
Reverse back this negative margin on the child of the NestedScrollView (in layout), or the 1st child of the RecyclerView (programmatically)
Put the scrolling view on top of the AppBarLayout so that the background of the AppBarLayout don't obscure the scrolling content to let them appear in the back of the toolbar.
Cosmetics:
Remove the elevation of the AppBarLayout to 0 to make it as not existing; just the ToolBar is there.
Set the background color of the AppBarLayout to transparent, so now it takes the background of the root layout.
Demo:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-100dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:text="#string/longText" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:background="#drawable/rounded_toolbar"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.material.appbar.MaterialToolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
For the RecyclerView, you can't control its children with layouts, so reversing the margin can either by
Having 2 layouts one with the 100dp top margin for the first child, another without margins for the rest children. And decide which layout in the adapter's onCreateViewHolder()
Adding the margin in adapter's onBindViewHolder():
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, final int position) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) holder.itemView.getLayoutParams();
if (position == 0) {
Resources resources = holder.itemView.getContext().getResources();
float dip = 100f;
float px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip,
resources.getDisplayMetrics()
);
params.topMargin = (int) px;
} else
params.topMargin = 0;
holder.itemView.setLayoutParams(params);
//...... rest of code
}
You should just wrap all widgets inside CoordinatorLayout with FrameLayout and change AppBarLayout position to the end:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context=".MainContentFragment">
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
...
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_margin="32dp"
android:background="#android:color/transparent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/holo_red_dark"
app:layout_scrollFlags="scroll|enterAlways">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
In an Android project, I have an Activity that contains (from top to bottom) a header, a RecyclerView and a RelativeLayout.
Code sample :
<android.support.design.widget.CoordinatorLayout ...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
...
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
This is the behaviour I want : the RelativeLayout is "folded" by default, i.e. under the RecyclerView. When the user swipes up, the RelativeLayout expands to use the whole screen, and folded again when swipes down.
What is the right way to do it ? As I want the RelativeLayout to be BELOW the RecyclerView when folded, and OVER it when expanded. I tried setting the dependencies between elements dynamically but couldn't manage to do so.
Thanks for any help or advice on how to organize the activity to get such a behaviour.
EDIT
This is the XML structure :
<CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</AppBarLayout>
<RecyclerView
android:id="#+id/top_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/app_bar"
android:layout_above="#+id/relativelayout_footer" />
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_alignParentBottom="true">
<TextView ...>
<RecyclerView
android:id="#+id/included_list"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="gone"/>
</RelativeLayout>
</RelativeLayout>
</CoordinatorLayout>
And the listener :
top_list.setVisibility(playlistOpened ? View.VISIBLE : View.GONE);
app_bar.setVisibility(playlistOpened ? View.VISIBLE : View.GONE);
included_list.setVisibility(playlistOpened ? View.GONE : View.VISIBLE);
Transition cb = new ChangeBounds();
cb.setDuration(1000);
TransitionManager.beginDelayedTransition(slider, cb);
playlistOpened = ! playlistOpened;
As you see, I switch the visibility of the elements in order to reorganise the view. When the included_list is set to VISIBLE, it pushes up the TextView.
The only problem is that the top_list and the app_bar disappear before being covered by the RelativeLayout. I tried adding a Listener to the Transition and do these when the transition ends, but it doesn't work (I guess because they're not set to GONE at the beginning, so the RelativeLayout can't move up). Any idea of how to do so ? Maybe I should open another question for it ?
Okay, a final attempt. I am back to RelativeLayout and added another one around the RecyclerView to fix its scrolling problem. However, transitions get tricky (and the listener complicated) then. In order to prevent the RecyclerView from popping away before the RelativeLayout with the TextView inside fully covers the latter, I had to include a fading transition to the RecyclerView, too. Hope this suits you.
XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/rlwithrecyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/rlwithtextview"
android:layout_alignParentTop="true">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/rlwithtextview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<TextView
android:layout_width="match_parent"
android:layout_height="400dp"
android:id="#+id/textview"
android:text="Just a test" />
</RelativeLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
onClick():
#Override
public void onClick(View v) {
RelativeLayout rlWithRecyclerView = findViewById(R.id.rlwithrecyclerview);
RelativeLayout.LayoutParams layoutParamsRlWithRecyclerView;
RelativeLayout rlWithTextView = findViewById(R.id.rlwithtextview);
RelativeLayout.LayoutParams layoutParamsRlWithTextView;
if (rlWithTextView.getLayoutParams().height == MATCH_PARENT) {
layoutParamsRlWithTextView = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
layoutParamsRlWithRecyclerView = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
layoutParamsRlWithRecyclerView.addRule(RelativeLayout.ALIGN_PARENT_TOP);
layoutParamsRlWithRecyclerView.addRule(RelativeLayout.ABOVE, R.id.rlwithtextview);
} else {
layoutParamsRlWithRecyclerView = new RelativeLayout.LayoutParams(MATCH_PARENT, 0);
layoutParamsRlWithTextView = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
}
layoutParamsRlWithTextView.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
Transition changeBounds = new AutoTransition();
changeBounds.setDuration(500);
TransitionManager.beginDelayedTransition(rlWithRecyclerView, changeBounds);
TransitionManager.beginDelayedTransition(rlWithTextView, changeBounds);
rlWithRecyclerView.setLayoutParams(layoutParamsRlWithRecyclerView);
rlWithTextView.setLayoutParams(layoutParamsRlWithTextView);
}
Although I got credit for the two other answers, I will eventually delete them, since they don't solve the problem.
ok im already doing (i believe) everything i need to do to make my applications layout scroll/move up when the soft keyboard is shown but it is not working so im guessing there must be something im doing stopping it, i wonder if its the fixed heights im giving my viewpagers or something im unaware of, ive read through posts that describe relative layouts as 'crushing child views' when the keyboard is shown and linear layouts not crushing child views, so with that in mind here are my layouts
MAIN_ACTIVITY
<?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"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/viewpagerHolder">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager2"
android:layout_width="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:layout_height="#dimen/card_pager_height" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/predictsHolder"
android:layout_below="#id/viewpager2">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager_predicts"
android:layout_width="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="4dp"
android:layout_height="#dimen/predicts_pager_height" />
</RelativeLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/predictsHolder"
app:tabGravity="fill"
android:theme="#style/CustomTabLayoutStyle" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tabs">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:background="#color/windowBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
</RelativeLayout>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/card_pager_height">
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
android:layout_marginEnd="12dp"
app:elevation="4dp"
android:src="#drawable/ic_playlist_play_white_24dp"
android:layout_gravity="right|top"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
There a total of 3 viewpagers each has a different layout the first (top most)
FIRST VIEWPAGER
<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"
android:background="#drawable/border"
android:paddingLeft="2dp"
android:paddingRight="2dp"
tools:context=".SpeakGridDB">
<android.support.v7.widget.RecyclerView
android:id="#+id/card_speak_grid"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
</RelativeLayout>
SECOND VIEWPAGER
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:background="#drawable/border">
<android.support.v7.widget.RecyclerView
android:id="#+id/predicts_card_speak_grid"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
</RelativeLayout>
THIRD VIEWPAGER
i would like this layout to still be present when the keyboard pops up its currently the bottom of the layout ive put it in a linear layout and also tried putting its viewpager in a linear layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/windowBackground"
tools:context=".OneFragment">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/activity_main_swipe_refresh_layout"
android:layout_width="match_parent"
android:background="#color/windowBackground"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/card_grid"
android:background="#color/windowBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"/>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
I'm also using
android:windowSoftInputMode="adjustResize"
in my manifest and have also tried
android:windowSoftInputMode="adjustPan"
but no joy it seems like the tabLayout shifts up slightly when keyboard is shown but generally the top two views stay in place and the bottom one (one i want shown) is hidden by the keyboard
any help is appreciated
UPDATE
still no further with this i can make a layout witht the fixed heights and have it scroll up perfectly with the softkeyboard shown so there not the problem but i must use layout center vertical on an element and this isnt what i want to do ive also tried wrapping it all in a scroll view and using isScrollContainer true but still no joy anyone got any ideas?
I may mistake, but cause of this problem is probably the known Android bug.
So, firstly, you need to add android:windowSoftInputMode="stateHidden|adjustResize" inside your <activity> tag.
Secondly, you need to add this class to your project:
public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}
And then simply use it by calling assistActivity() method in your MainActivity that holds ViewPagers:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
AndroidBug5497Workaround.assistActivity(this);
...
}
For more background check this thread.
You can try adding android:fitsSystemWindows="true" to your coordinator layout
I already showed my bottom sheet layout with its peek height set to 100dp. But how can I limit my bottom sheet to expand to 500dp only? This is my sample layout:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
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">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />
<android.support.v4.widget.NestedScrollView
android:id="#+id/design_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
app:behavior_hideable="true"
app:behavior_peekHeight="100dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_margin="#dimen/activity_horizontal_margin"
app:layout_anchor="#+id/design_bottom_sheet"
app:layout_anchorGravity="top|right|end"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.design.widget.CoordinatorLayout>
In addition to my question, how can I disallow the user from dragging the bottom sheet up and down?
to stop the bottom sheet from moving up the full screen is simple, just set a layout_height for your NestedScrollView to 500dp, also you probably want to set it's layout_gravity="bottom"
<android.support.v4.widget.NestedScrollView
android:id="#+id/design_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#000000"
android:layout_gravity="bottom"
app:behavior_hideable="true"
app:behavior_peekHeight="100dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="5dp"
android:background="#e444ff" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
if you don't want the view to be draggable up then you need to set behavior_peekHeight and layout_height to the same values.
And to stop the view from being draggable down is the behavior_hideable flag just set this to false
You can use setMaxHeight method from BottomSheetBehavior (this method should be called before show() method)
bottomSheetDialog.behavior.maxHeight = 1000 // set max height when expanded in PIXEL
bottomSheetDialog.behavior.peekHeight = 400 // set default height when collapsed in PIXEL
You can just set param "maxHeight" to the root viewgroup of your bottom sheet.
android:maxHeight=500dp
Works good with ConstraintLayout as root layout.
If using BottomSheetDialogFragment:
In my case I was using BottomSheetDialogFragment and modified the bottom sheet peek height by getting its reference by override OnCreateDialog method inside my BottomSheetFragment
#NonNull #Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
BottomSheetDialog bottom_dialog = (BottomSheetDialog) dialog;
FrameLayout bottomSheet = (FrameLayout) bottom_dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
assert bottomSheet != null;
//BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
DisplayMetrics displayMetrics = requireActivity().getResources().getDisplayMetrics();
int height = displayMetrics.heightPixels;
int maxHeight = (int) (height*0.80);
BottomSheetBehavior.from(bottomSheet).setPeekHeight(maxHeight);
}
});
return dialog;
}
Above solutions didn't work for me so I solved it by
1. added app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" in the root view of bottom sheet layout.
2. custom style for bottom sheet:
<style name="AppBottomSheetDialogTheme" parent="Theme.MaterialComponents.BottomSheetDialog">
<item name="bottomSheetStyle">#style/AppModalStyle</item>
</style>
<style name="AppModalStyle" parent="Widget.MaterialComponents.BottomSheet">
<item name="behavior_peekHeight">600dp</item>
</style>
3. And using this in Activity or Fragment by
val mBottomSheetDialog = BottomSheetDialog(this, R.style.AppBottomSheetDialogTheme)
val inflater = this.layoutInflater
val sheetView = inflater.inflate(R.layout.bottom_sheet_layout, null)
mBottomSheetDialog.setContentView(sheetView)
mBottomSheetDialog.show()
For some reason, the accepted answer didn't work for me. Maybe because I'm not using a fragment and a NestedScrollView as the layout inside my BottomSheet. Anyway, in my case, the solution was to limit the size of the CoordinatorLayout:
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your main content here -->
</ConstarintLayout>
<CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="MAX SIZE OF BOTTOM SHEET">
<YourBottomSheetLayout>
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</CoordinatorLayout>
</ConstarintLayout>