RecyclerView Header under items in Android - android

I can't find solution for such behaviour:
It is that header of the RecyclerView is a little bit under items. Of course I guess that it is RecyclerView.
How can I achieve that?
EDIT
What I have done is just adding decoration for recycler view.
This is my simple decorator:
public class HeaderItemDeceration extends RecyclerView.ItemDecoration {
public HeaderItemDeceration() {
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.bottom = -100;
}
}
}
It's working but the problem is that this header is disappearing too fast, I mean where next item is on the top, and under it there is header, and immediately is disappearing, because normally it should be hidden when next item is on the top.
EDIT 2
I haven't explain everything, so here I'm explaining.
In my case I don't want to have ActionBar. What I want is just image under RecyclerView like in example above, but without collapsing toolbar. Just let's say that my Activity has style which parent is Theme.AppCompat.Light.NoActionBar.
Taking into consideration my explanation and answers below I'm trying to reach the goal with such 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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="fitXY"
android:src="#drawable/header"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_items"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:behavior_overlapTop="24dp"/>
</android.support.design.widget.CoordinatorLayout>
It's almost working. Almost, because I noticed unwanted effect, which is when I scroll to top sometimes I have to repeat scroll gesture to reach the top. I recorded it:
Bad effect recorded
I assume that with my goal using CollapsingToolbarLayout may be wrong.

I achieved this effect when I wrote the main home screen for the lawn care app for Scotts. Here is an image of how it looks.
This is accomplished by using a CoordinatorLayout, AppBarLayout, CollapsingToolbarLayout, and RecyclerView. The key is a scrolling view behavior you need to set both app:behavior_overlapTop and app:layout_behavior="#string/appbar_scrolling_view_behavior" attributes on the RecyclerView (which only work if it's a sibling view of an AppBarLayout).
In my scenario, I had the header separate from the RecyclerView altogether. Depending on how your content is managed, this solution may not work for you (although it is a lot simpler for me to keep the header outside of the RV--one less viewtype/view holder to manage!)
The gist ends up looking like this:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<android.support.design.widget.AppBarLayout
android:layout_height="300dp" // fixed height of your header container
android:layout_width="match_parent"
android:fitsSystemWindows="true"
>
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" // snap/exitUntilCollapsed are optional. See more info on scroll flags here: https://developer.android.com/reference/android/support/design/widget/AppBarLayout.LayoutParams.html#setScrollFlags(int)
>
<ImageView // This is where you'd put your header backdrop
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax" // not essential, but most people want the parallax scrolling effect with their image header in this setup. this is how you would do it.
/>
</CollapsingToolbarLayout>
</AppBarLayout>
<RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:behavior_overlapTop="64dp" // This is what you're looking for!
/>
</CoordinatorLayout>

Its a combination of two view, not just a recycler view.
Android-ObservableScrollView will help you to reach what you want.
The trick is, there is a view in background and a recycler in front. The recycler view have a header which make the gap you want from top.
Whenever you scroll the recycler, you will get notified by the listener you used and in that you will scroll the bottom layout manually,

try all possible combinations of layout_scrollFlags of AppBarLayout it will help in improvement in scroll
app:layout_scrollFlags="scroll|snap" //try this it will work for you
app:layout_scrollFlags="scroll|exitUntilCollapsed" // ur current scroll
app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
app:layout_scrollFlags="scroll|enterAlways"
and read scrolling-techniques-for-material-design

Related

CoordinatorLayout content child overlaps BottomNavigationView

I'm trying to use a CoordinatorLayout with a BottomNavigationView, an AppBarLayout, and a ViewPager. Here is my 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</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.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="#menu/navigation"/>
</android.support.design.widget.CoordinatorLayout>
The problem is that the CoordinatorLayout places the ViewPager to extend to the bottom of the screen, so the bottom is obscured by the BottomNavigationView, like this:
This happens even though the CoordinatorLayout itself doesn't extend down so far:
I've tried adding app:layout_insetEdge="bottom" to the BottomNavigationView and app:layout_dodgeInsetEdges="bottom" to the ViewPager, but that has a different problem: it shifts the bottom of the ViewPager up, but it keeps the same height, so the top is now chopped off:
I tried two other experiments. First, I tried removing the BottomNavigationView from the CoordinatorLayout and making them siblings under a vertical LinearLayout. Second, I put the ViewPager and BottomNavigationView together under a LinearLayout, hoping they would layout out correctly. Neither helped: in the first case, the CoordinatorLayout still sized the ViewPager with respect to the entire screen, either hiding part of it behind the BottomNavigationView or chopping off the top. In the second case, the user needs to scroll to see the BottomNavigationView.
How do I get the layout right?
P.S. When I tried the layout suggested by #Anoop S S (putting the CoordinatorLayout and the BottomNavigationView as siblings under a RelativeLayout), I get the following (with the ViewPager still extending down behind the BottomNavigationView):
As before, the CoordinatorView itself only extends down to the top of the BottomNavigationView.
I came up with a different approach (not battle tested yet though):
I subclassed AppBarLayout.ScrollingViewBehavior to adjust the bottom margin of the content view based on the height of the BottomNavigationView (if present). This way it should be future proof (hopefully) if the height of the BottomNavigationView changes for any reason.
The subclass (Kotlin):
class ScrollingViewWithBottomNavigationBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
// We add a bottom margin to avoid the bottom navigation bar
private var bottomMargin = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
return super.layoutDependsOn(parent, child, dependency) || dependency is BottomNavigationView
}
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
val result = super.onDependentViewChanged(parent, child, dependency)
if(dependency is BottomNavigationView && dependency.height != bottomMargin) {
bottomMargin = dependency.height
val layout = child.layoutParams as CoordinatorLayout.LayoutParams
layout.bottomMargin = bottomMargin
child.requestLayout()
return true
} else {
return result
}
}
}
And then in the layout XML you put:
app:layout_behavior=".ScrollingViewWithBottomNavigationBehavior"
instead of
app:layout_behavior="#string/appbar_scrolling_view_behavior"
Basically what you have to do is create a Relativelayout as parent and put BottomNavigationView and CoordinatorLayout as children. Then align BottomNavigationView at the bottom and set CoordinatorLayout above that. Please try the below code. It might have few attribute erros, because I wrote it here itself. And sorry for the messed up indentation.
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/navigation"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</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>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="#menu/navigation"/>
</RelativeLayout>
This is caused by app:layout_behavior="#string/appbar_scrolling_view_behavior" in your ViewPager. If you remove this line, you will see now it fits the CoordinatorLayout container (unfortunately, this includes now being underneath the Toolbar).
I found it helped to treat CoordinatorLayout as just a FrameLayout, with a few extra tricks. The app:layout_behavior attribute above is necessary to allow the toolbar to appear to scroll in and out... in reality, the layout is doing this by having the view linked to the collapsing toolbar (in your case, your ViewPager) be exactly a toolbar's height larger than the bounds. Scrolling up brings the view up to the bottom within the bounds, and pushes the toolbar up extending beyond the bounds. Scrolling down, vice versa.
Now, onto the BottomNavigationView! If, as I did, you want the BottomNavigationView visible the whole time, then move it outside the CoordinatorLayout, as Anoop said. Use CoordinatorLayout only for things that need to coordinate, everything else outside. I happened to use a ConstraintLayout for my parent view (you could use RelativeLayout or whatever works for you though). With ConstraintLayout, for you it would look like this:
<android.support.constraint.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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</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>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
In Android Studio design view, you're still going to see the ViewPager appear to be larger than the container (probably looks like it's behind the Bottom Nav still). But that's ok, when you get to the bottom of the ViewPager's content, it will show (i.e. won't be behind the bottom navigation). This quirk in the design view is just the way the CoordinatorLayout makes the toolbar show/hide, as mentioned earlier.
I had a similar problem with a layout very close to OP's and a ViewPager with 3 pages but only page 2 and 3 which should be affected by appbar_scrolling_view_behavior.
After struggling for hours exploring dead-end possible solutions (layout_dodgeInsetEdges, Window insets, attempting to modify ViewPager's page measured size, android:clipChildren, fitSystemWindows, ...), I finally found an easy solution detailed below.
As Vin Norman explained, ViewPager overlapping BottomNavigation is entirely caused by appbar_scrolling_view_behavior set on the ViewPager. AppBarLayout will just make fullscreen the sibling that has appbar_scrolling_view_behavior. That's how it works.
If you only need this behavior on certain ViewPager pages, there is a simple fix than you can apply on the ViewPager's OnPageChangeListener to dynamically change the Behavior and add/remove required padding:
public class MyOnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
#Override
public void onPageSelected(int position) {
...
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) _viewPager.getLayoutParams();
if(position == 0) {
params.setBehavior(null);
params.setMargins(params.leftMargin, _appBarLayoutViewPagerMarginTopPx,
params.rightMargin, _appBarLayoutViewPagerMarginBottomPx);
} else {
params.setBehavior(_appBarLayoutViewPagerBehavior);
params.setMargins(params.leftMargin, 0, params.rightMargin, 0);
}
_viewPager.requestLayout();
}
}
For page at position 0 (the one we want the ViewPager to extend exactly below the Toolbar and above the BottomNavigationView), it removes the behavior and adds top and bottom padding, respectively _appBarLayoutViewPagerMarginTopPx and _appBarLayoutViewPagerMarginBottomPx that are constants easy to compute beforehand (respectively the value in pixel for R.attr.actionbarSize and the height for the NavigationBottomView. Usually both are 56dp)
For all other pages needing appbar_scrolling_view_behavior we restore the associated scrolling behavior (stored beforehand in _appBarLayoutViewPagerBehavior) and remove top and bottom padding.
I tested this solution and it works fine without caveat.
In case anyone is still searching for a solution of this problem:
Cause of the problem is that CoordinatorLayout is not calculating correctly size of AppBarLayout because it has Toolbar with app:layout_scrollFlags="enterAlways|scroll" setting. It thinks that Toolbar will hide when scrolling so it leaves all available space to ViewPager, but actually what happens is that toolbar shows so ViewPager moves down, behind NavigationBar.
Easiest way to solve this is just to add android:minHeight="?attr/actionBarSize" (or whatever toolbar height you are using) to AppBarLayout. This way CoordinatorLayout will know properly how much space it needs to leave for ViewPager.
If it still matters to someone:
In the answer of Anoop SS above, trying replacing the RelativeLayout with LinearLayout. Also set layout_height of CoordinatorLayout to 0dp and set layout_weight to 1.
I had almost the same problem....just that i wanted to have a static AdView at the bottom instead of the BottomNavigationView. Trying Anoop SS suggestions, at first, I got the same behaviour as OP: ViewPager extended behind the AdView. But then I did what I suggested about and everything worked fine.
Android layouts behave in weird manner or may be it is the lack of good documentation or the lack of knowledge on our part....but making a layout is just too annoying most of the time.
If you are using Androidx try this
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_above="#+id/bottomNavView">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.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" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/mobile_navigation" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:menu="#menu/bottom_nav" />

RecyclerView and a view collapsed on tap causes RecyclerView to "jump" on scroll

I have a RecyclerView which has children that expand on tap. I also have a CollapsingToolbarLayout at the top of this screen that collapses when the child of the RecyclerView expands. This is intended however when I then scroll on the RecyclerView, the collapsed view will suddenly expand to full size.
I assume this is happening because when the child is expanded and the toolbar collapses, it thinks the user has collapsed it on scroll. But because no touch was involved, when I subsequently scroll myself the RecyclerView still believes the view was where it was.
Any idea how to either stop the automatic collapsing or get the RecylerView to update with the position of the collapsed view?
Code, if necessary:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/lytChanges"
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="89dp"
android:background="#color/colorPrimary"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll">
<reroo.reroo.CustomViews.FontText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="#dimen/itinerary_changes_margin_top"
android:background="#android:color/transparent"
android:text="Changes:"
android:textAlignment="center"
android:textColor="#B3ffffff"
android:textSize="16sp"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!--</android.support.percent.PercentRelativeLayout>-->
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="#color/grey"
android:focusable="false"
android:foreground="?android:attr/selectableItemBackground"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
EDIT 1: I have tried adding enterAlways, enterAlwaysCollapsed and exitUntilCollapsed to my xml but I believe this is an issue with the RecyclerView not tracking its position after it has animated with the child expanding.
EDIT 2: Using notifyItemChanged(position) after child tap causes the RecyclerView to animate the expansion and collapse, and then subsequently animate the un-collapsing of the view without any user input.
Preferred behaviour:
animate and collapse. Stay. or
don't animate and collapse, but collapse on scroll

How to fix footer properly which is inside CoordinatorLayout

I tend to further elaborate from this
Android - footer scrolls off screen when used in CoordinatorLayout
and
https://code.google.com/p/android/issues/detail?id=177195
I wish to hide TabLayout while performing scrolling on RecyclerView. That's why I have the following layout.
<CoordinatorLayout>
<CollapsingToolbarLayout>
<TabLayout>
<ViewPager>
<RecyclerView>
<Footer>
For my situation, I have a ViewPager which contains multiple fragments.
Most of the fragments, contains RecyclerView and footer. They look like the following
<LinearLayout>
<RecyclerView />
<LinearLayout id="#+id/footer" />
</LinearLayout>
Unfortunately, the footer is movable when scrolling, although I would like it to be static.
Note, it is important to have app:layout_behavior to place in ViewPager instead of RecyclerView. If not, TabLayout will not appear.
My implementation is as follow
my_fragment.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"
android:id="#+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" >
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways|snap">
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="?attr/portfolioTabIndicatorColor" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="org.yccheok.xxx.CustomScrollingViewBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
The very key class is org.yccheok.xxx.CustomScrollingViewBehavior, which is copied and pasted from https://stackoverflow.com/a/33396965/72437
org.yccheok.xxx.CustomScrollingViewBehavior is the best solution I can find so far. However, it is far from perfect, as it yields the following behavior.
It causes flickering, when you scroll up a little, and release your finger. Please refer to the following video.
https://youtu.be/8RvCZJeQvS0
I was wondering, based on proposed solution at https://stackoverflow.com/a/33396965/72437, is there any further improvement I can done on CustomScrollingViewBehavior class, to avoid flickering effect?
I was able to achieve what I want, by following tutorial at
https://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling%28part1%29/
http://mzgreen.github.io/2015/02/28/How-to-hideshow-Toolbar-when-list-is-scrolling%28part2%29/
The key ideas are
Don't use CoordinatorLayout
Place TabLayout and RecyclerView within FrameLayout, so that TabLayout will overlay on the top of RecyclerView
Add top padding on RecyclerView. Having android:clipToPadding="false" is important as well.
To hide/ show TabLayout during scrolling, attach HidingScrollListener to RecyclerView.
The shortcoming for this solution is that, requiresFadingEdge will no longer work on RecyclerView, due to the top padding.

Slide RecyclerView up as you swipe it up, or slide recyclerview down as you swipe down

I want to create a Fragment with a RecyclerView that slides up and shows more items as you slide it up.
Here is an example of what I am talking about.
Initial Creation:
User Swipes Up to slide RecyclerView up, shows more items:
There are a few issues, I would like to not use a CoordinatorLayout, and I would like to set it to where the items in the RecyclerView stack up directly on top of the EditText.
This is the layout code I am using:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/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:visibility="visible">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<View
android:id="#+id/emptyView"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#android:color/transparent"
app:layout_collapseMode="parallax"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="#+id/editText"
android:paddingLeft="16dp"
android:inputType="textAutoCorrect"
android:layout_centerVertical="true"
android:background="#android:color/transparent"
android:layout_width="match_parent"
android:layout_height="56dp"/>
</RelativeLayout>
</RelativeLayout>
And I get something like this:
This is definitely not scalable, and empty view would need to be consistently measured.
I solved this by using a custom TouchListener all of the other solutions were very basic and limited to a specific and boxed use-case.
The way I did this was to implement a new TouchListener based off of this library:
BounceTouchListener
I get the following results:
Use RecyclerView with 2 types of rows:
Empty row/rows colored gray (without divider)
Rows with content as you already have
The RecyclerView will have to match_parent to the entire fragment
So you will get the right effect of a "blank" area on top of the RecyclerView.
You can use setReverseLayout of LinearLayoutManager
Used to reverse item traversal and layout order. This behaves similar
to the layout change for RTL views. When set to true, first item is
laid out at the end of the UI, second item is laid out before it etc.
For horizontal layouts, it depends on the layout direction. When set
to true, If RecyclerView is LTR, than it will layout from RTL, if
RecyclerView} is RTL, it will layout from LTR. If you are looking for
the exact same behavior of setStackFromBottom(boolean), use
setStackFromEnd(boolean)

Programmatically show Toolbar after hidden by scrolling (Android Design Library)

I have the following layout: a drawer, with the main content view having a AppBarLayout, RecyclerView and a TextView. When I scroll the recycler, the toolbar is correctly hidden.
However, I have a use case: when all items from the recycler are removed, I sets its visibility to 'gone' and a TextView with an appropriate message it shown instead. If this is done while the toolbar is hidden, it is not possible for the user to see the toolbar again.
Is it possible to programmatically cause the toolbar to be fully shown? I would do this whenever the TextView is shown instead of the RecyclerView.
Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<android.support.design.widget.CoordinatorLayout
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">
<Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/test_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<TextView
android:id="#+id/empty_test_list_info_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="#dimen/spacing_big"
android:textAppearance="?android:attr/textAppearanceLarge"
android:visibility="gone"/>
</android.support.design.widget.CoordinatorLayout>
<RelativeLayout
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="?android:attr/windowBackground"
android:elevation="10dp"/>
</android.support.v4.widget.DrawerLayout>
BTW, for some reason, if I put the AppBarLayour after the RecyclerView, as all tutorials seem to show it, it hides the topmost item from the list. It only works correctly when it is above it.
You can do it by accessing to the AppBarLayout that contains your Toolbar
Here is an example:
if (mToolbar.getParent() instanceof AppBarLayout){
((AppBarLayout)mToolbar.getParent()).setExpanded(true,true);
}
setExpanded(expand,animation) will do the work.
You can also have a a reference to the AppBarLayout instead of call the getParent from the toolbar.
You need to put header to the RecyclerView to the height of the AppBarLayout. I.e at position 0 of the RecyclerView you need to add the header and then the rest of the elements.
If you want to forcefully show the Toolbar, actually the AppBarLayout with offsetting top and bottom of the AppBarLayout dependent views (it is called Behavoir) . You need to keep reference of height of the AppBarLayout, as we know that height is the distance between top and bottom of view Rect.
Assuming that your AppBarLayout hold only a Toolbar:
int mAppBarLayoutHeight = mAppBarLayout.getBottom() - mAppBarLayout.getTop(); //initial, normal height
private void showToolbar(){
if(this.mAnimator == null) {
this.mAnimator = new ValueAnimator();
this.mAnimator.setInterpolator(new DecelerateInterpolator());
this.mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedOffset = (int) animation.getAnimatedValue();
mToolbar.offsetTopBottom(animatedOffset/2);
}
});
} else {
this.mAnimator.cancel();
}
this.mAnimator.setIntValues(0, mAppBarLayoutHeight);
this.mAnimator.start();
}
U could either do toolbar.transitionY(int y); on the on scroll method or use visibility gone and u have to add an header in the list view or recycler view with the size of the toolbar. So that the whole list still shows

Categories

Resources