RecyclerView smoothScrollToPosition(lastItem) scrolls to bottom where last item is partially visible - android

Im working on chat type screen where new text msg item is added in list and recyclerView is scrolled to last position of the list but the last item is partially visible, and does not scroll till end of bottom when the keyboard is open. I have added
android:layout_width="match_parent"
android:gravity="top"
android:layout_gravity="fill_vertical"
android:windowSoftInputMode="adjustResize"
android:clipToPadding="false"
android:layout_height="match_parent"
app:layout_constrainedHeight="true"
app:layout_scrollFlags="scroll|enterAlways"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginBottom="#dimen/margin_5"
to the recycler view.
I have also tried to use recyclerView.layoutMangaer.smoothScrollToPosition, ScrollBy() method, and also used some 300 msec delay to scroll.
Nothing worked.
Will appreciate some help. Thanks.

Related

Recyclerview inside NestedScrollView - Scroll to bottom

I have a RecyclerView inside a NestedScrollView:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="#dimen/_100sdp">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_chat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="#dimen/_100sdp"
android:layout_marginLeft="#dimen/_30sdp"
android:layout_marginRight="#dimen/_30sdp"
android:background="#color/bright_grey"
></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.NestedScrollView>
My RecyclerView is being filled with items in onCreate()
On a device you would see the first item of the RecyclerView on the very top und would have to scroll down the NestedScrollView in order to see the last item.
Since my items are chat message sorted by the time sent I need the NestedScrollView to be scrolled all the way down so users would see the latest chat message first without having to scroll in the first place.
Any ideas on this?
Given that your RecyclerView is the only child of your NestedScrollView, you would be better off removing the NestedScrollView altogether, and instead applying the fixed height to the RecyclerView. Something like this:
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_chat"
android:layout_width="match_parent"
android:layout_height="#dimen/_100sdp"
android:layout_marginLeft="#dimen/_30sdp"
android:layout_marginRight="#dimen/_30sdp"
android:background="#color/bright_grey" />
Doing this allows you to have the RecyclerView itself manage scrolling, rather than the parent scroll view. And that allows you to leverage a property of LinearLayoutManager to achieve what you want.
Reverse layout -- setting this will "invert" your list; the first item in your adapter will appear at the bottom of the list, and the default scroll position of the RecyclerView will be to scroll all the way to the bottom.
https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html#setReverseLayout(boolean)
LinearLayoutManager lm = new LinearLayoutManager(this);
lm.setReverseLayout(true);
If you have the same issue and want to keep the NestedScrollView.
It will work like this.
Handler(Looper.getMainLooper()).postDelayed({
binding.nestedScrollView.smoothScrollTo(
0,
binding.recyclerview.measuredHeight,
500
)
// binding.nestedScrollView.scrollTo(0, binding.recyclerview.measuredHeight)
// binding.nestedScrollView.smoothScrollTo(0, binding.recyclerview.measuredHeight)
}, 50L)
For me, it didn't work without delay.

Move layout up when layout above shrinks in height

Hi I have a fragment with two RecyclerViews in it, one above the other.
The first is a list of items for the user to take an action on and the second is where the items will be populated once the action is taken. So when an item is removed from the top list it is added to the bottom list.
The issue I am having is when I remove an item from the top RecyclerView all the remaining items in the top RecyclerView move up to fill in the space left by the removed item, but this leaves a gap between the top and bottom RecyclerViews.
How can I move the bottom recyclerview up to fill in the gap created once an item is removed from the top RecyclerView
Here is my layout xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_alignParentTop="true"
android:id="#+id/pending_tasks"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:layout_below="#id/pending_tasks"
android:id="#+id/completed_tasks"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
I have tried calling invalidate() on the bottom RecyclerView but that has not worked. Any help would be appreciated, thanks!
It's impossible to update layout size once it's been displayed on the screen. If you modify the content of your RecyclerView you can't just simply refresh the layout to shrink it.
I would suggest using single RecyclerView and storing lower bound of the first list in some variable. Then simply update it accordingly to modifications in your first list.
Another solution which may help you:
Change Relative layout width and height dynamically

Android three levels recyclerview

I've been puzzling now on this quite a while.....
In my activity I have a recyclerview with a row adapter (vertical). In each row I have a recyclerview with a panel adapter (horizontal). In each panel I have a recyclerview with an item adapter (vertical).
Everything works fine but when I try to scroll the items the rows are scrolling, not the items.
What I want is that the items will scroll, unless there are not enough items in a panel to scroll, (like in panel B3) then the rows should be scrolling. In case there are enough items in a panel to scroll and I reach top or bottom of the items in a panel, then the rows should start scrolling.
Can anyone point me in the right direction?
Make sure your layout is inside NestedScrollView:
<android.support.v4.widget.NestedScrollView
android:id="#+id/nScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<FrameLayout ...>
<android.support.v7.widget.RecyclerView
.........
</android.support.v7.widget.RecyclerView>
</FrameLayout >
</android.support.v4.widget.NestedScrollView>
try:
mRecyclerView.setNestedScrollingEnabled(true);

SwipeRefreshLayout not working when first item has a height of 0

SwipeRefreshLayout does not work (animation not shown, onRefresh not called) when the first item in the RecyclerView within the SwipeRefreshLayout has a height of zero.
You can check out a test project on Github that shows this.
My question is: can this effect be circumvented?
In my actual project, due to circumstances not in my hand (Ad library)the first item of my list will sometimes have a height of 0, so setting it to View.GONE or height to 1 is not an option.
Found an workaround: Put RecyclerView to into additional view:
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
it cause additional overdraw, but works
few more suggestions found here: https://github.com/airbnb/epoxy/issues/74
If you can get a callback from the ad library you should be able to work around the bug by adding and removing the advertisement item from your RecyclerView.Adapter depending on whether or not the ad view has content to display.

NestedScrollView (NSV) in CoordinatorLayout (CL): NSV Not at Top When Loaded

I am using an NSV in a CL for the ability to have the toolbar compress when the NSV scrolls down. The problem that I am having is that my NSV is not scrolled to the top when it loads, instead, it is offset from the top of the NSV by quite a margin (I am not certain where this spacing is coming from, it's not in the layout).
Please take a look at the screen captures, the first one shows how the NSV loads and you can clearly see the NSV has scrolled down quite a bit from the top by comparing the second (when I scroll the NSV to the top manually):
I did some updates to this layout and it caused this to occur, previously, it loaded at the top without issue. However, I did not add any spacing that should have caused this.
Here is the layout I'm using for this:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/cl_goal_detail"
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="0dp"
android:layout_weight="1">
<android.support.design.widget.AppBarLayout
android:id="#+id/abl_goal_detail"
android:layout_width="match_parent"
android:layout_height="144dp"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/content_space_double"
app:collapsedTitleTextAppearance="#style/title.dark"
app:expandedTitleTextAppearance="#style/display3.plus.dark"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_goal_detail"
style="#style/toolbar"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/nsv_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/content_space_half"
android:paddingLeft="#dimen/content_space_half"
android:paddingRight="#dimen/content_space_half"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/container_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Any ideas would be appreciated!
OK! After a solid DAY of debugging every single component of my layout and Fragment I identified what I believe is a bug.
First, the issue: Turns out that having elements in your NSV's child view that change visibility to View.GONE upon runtime are causing the list to scroll down. I noticed that the list scrolls to just above the element where the visibility was toggled (including any margins set on the view).
Second, the fix: I fixed this issue by setting all the views to have android:visibility="gone" in the xml layout, then, I toggle each view's visibility as needed. Previously, the views were visible by default and then I worked from there. I just needed to change my logic to start with them all GONE, not terribly difficult.
I assume this works because the views you are going to hide at runtime do not form a part of the overall height calculation when the NSV is created in onCreateView(). Once the fragment progresses past onCreateView() it's safe to dynamically change the views, however, if the views are calculated as part as the height in onCreateView() and THEN hidden with View.GONE, measurements go wonky and you end up with a list scrolled down significantly.
Have you tried adding below line in your viewgroup i.e. FrameLayout in your case
android:descendantFocusability="blocksDescendants"
I think this will also work for you.
If not try it adding in NSV.
In my case, there was an EditText near the bottom of my scrolling content that was grabbing focus. Since NestedScrollView does some weird layout stuff, the focused view didn't scroll to the top when the activity started, so the real cause was not readily apparent. Adding this to the NestedScrollView's child layout fixed it for me:
android:focusableInTouchMode="true"
Your post answer helped me a lot to find out my issue (btw, it was the same). But I got it worked in a different way. I guess you are using a RecyclerView. In my case I'm using 3 RecyclerViews. Well, from your answer I started hiding the recyclers and I found out just one of them was causing this issue. What I did is I populated with a postDelayed:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
recyler.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyler.setAdapter(new MyAdapter(myList));
}
}, 3000);
That worked fine!

Categories

Resources