I have a recycler view and a banner AD in fragment view and i want to scroll ad with the recycler view when i scroll it down.
i am using nested scroll for it and ad is scrolling fine initially. but when i scroll it down and more data comes from server then its not remain smooth and stopping some times.
I have tried every sol on stack but nothing working for me.
Here is some code.
fragment_all.xml :
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:id="#+id/nestedScroll"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.gms.ads.AdView
android:id="#+id/adView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:visibility="gone"
android:focusableInTouchMode="true"
ads:adSize="BANNER"
ads:adUnitId="ca-app-pub-3940256099942544/6300978111">
</com.google.android.gms.ads.AdView>
<android.support.v7.widget.RecyclerView
android:id="#+id/news_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:nestedScrollingEnabled="false"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
fragment_all.java :
nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
#Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if(v.getChildAt(v.getChildCount() - 1) != null) {
if ((scrollY >= (v.getChildAt(v.getChildCount() - 1).getMeasuredHeight() - v.getMeasuredHeight())) &&
scrollY > oldScrollY) {
visibleItemCount = layoutManager.getChildCount();
totalItemCount = layoutManager.getItemCount();
pastVisibleItems = ((LinearLayoutManager) recyclerView.getLayoutManager())
.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisibleItems) >=totalItemCount) {
if (!loadingInside) {
loadingInside = true;
postNo = postNo + 15;
getDataFromUrl(postNo);
}
}
}
}
}
});
NOTE : i have tried solutions like :
<app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:nestedScrollingEnabled="false"/>
Please set this
rec_view_notification.setLayoutManager(new LinearLayoutManager(getContext(),
LinearLayoutManager.VERTICAL, false) {
#Override
public boolean canScrollHorizontally() {
return false;
}
#Override
public boolean canScrollVertically() {
return false;
}
});
You can set your RecyclerView Nested Scrolling false
Like
recyclerViewSignup.setNestedScrollingEnabled(false);
Related
I have a View and a RecyclerView housed in a LinearLayout. What I want to achieve is something like this:
https://material.google.com/patterns/scrolling-techniques.html#scrolling-techniques-behavior
Basically when I scroll the RecyclerView up, the View collapses. It expands if I scroll the RecyclerView down.
I've tried various methods but the animation stutters if the finger jerks around a scroll position. It only animates well if the finger does a deliberate scroll movement in one direction. How do I do this correctly?
You have to use Coordinator Layout with the CollapsingToolbarLayout
<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:clipToPadding="false">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="210dp"
android:stateListAnimator="#animator/appbar_always_elevated" //I put this here because I want to have shadow when is open, but you have to create the xml file.
android:background="#color/WHITE">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="#style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="#style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
app:layout_scrollFlags="scroll|exitUntilCollapsed"> //HERE you should take a look what you want your collapse bar do.
<Here you put the content for you collapse bar, like a ImageView>
<android.support.v7.widget.Toolbar //This is the size of your fixed bar when you collapse, even here you can put a back button, for example
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="40dp"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/main_home_list_swipe"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<android.support.v7.widget.RecyclerView
android:id="#+id/main_home_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout >
Obs: the comments will give errors if you put on a xml file. Is on propose so you will remember to read hahahah
Try this:-
I also want this kind of animation on custom view and i have achieved it this way.
public class TestActivity extends AppCompatActivity {
private static final int HIDE_THRESHOLD = 20;
//this is you custom layout it is any thing.
LinearLayout customLayout;
private int scrolledDistance = 0;
private boolean controlsVisible = true;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
scrolledDistance = dy;
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
hideViews();
controlsVisible = false;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
showViews();
controlsVisible = true;
}
}
});
}
private void hideViews() {
customLayout.animate().translationY(-customLayout.getHeight()).setInterpolator(new AccelerateInterpolator(2));
}
private void showViews() {
customLayout.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
}
}
Edit - 1
for ScrollView try this listener
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
hideViews();
controlsVisible = false;
scrolledDistance = 0;
} else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
showViews();
controlsVisible = true;
scrolledDistance = 0;
}
}
});
Hope it also helps you...
To achieve toolbar to expand and collapse smoothly you can apply translate animation or use CoordinatorLayout with AppBarLayout and Toolbar.
Animation : First you have to detect scroll up and scroll down on your RecyclerView. To do so you can set “setOnScrollListener” on your RecyclerView. Once you have both scroll up and scroll down, simply apply animation.
Code:
rvHomeList.setOnScrollListener(new RecyclerView.OnScrollListener() {
int verticalOffset;
boolean scrollingUp;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (scrollingUp) {
Log.e("onScrollStateChanged", "UP");
if (verticalOffset > llTop.getHeight()) {
toolbarAnimateHide();
}
} else {
Log.e("onScrollStateChanged", "down");
if (llTop.getTranslationY() < llTop.getHeight() * -0.6 && verticalOffset > llTop.getHeight()) {
toolbarAnimateHide();
} else {
toolbarAnimateShow(verticalOffset);
}
}
}
}
#Override
public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
verticalOffset += dy;
scrollingUp = dy > 0;
int toolbarYOffset = (int) (dy - llTop.getTranslationY());
llTop.animate().cancel();
if (scrollingUp) {
Log.e("onScrolled", "UP");
if (toolbarYOffset < llTop.getHeight()) {
llTop.setTranslationY(-toolbarYOffset);
} else {
llTop.setTranslationY(-llTop.getHeight());
}
} else {
Log.e("onScrolled", "down");
if (toolbarYOffset < 0) {
llTop.setTranslationY(0);
} else {
llTop.setTranslationY(-toolbarYOffset);
}
}
}
});
Animation Methods:
private void toolbarAnimateShow(final int verticalOffset) {
if (!isShowing) {
isShowing = true;
llTop.animate()
.translationY(0)
.setInterpolator(new LinearInterpolator())
.setDuration(180)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
llTop.setVisibility(View.VISIBLE);
isShowing = false;
}
});
}
}
private void toolbarAnimateHide() {
if (!isHidding) {
isHidding = true;
llTop.animate()
.translationY(-llTop.getHeight())
.setInterpolator(new LinearInterpolator())
.setDuration(180)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
llTop.setVisibility(View.GONE);
isHidding = false;
}
});
}
}
CoordinatorLayout with AppBarLayout and Toolbar: By using coordinatorLayout with appBarLayout and toolbar, and set the scroll flag used within the attribute app:layout_scrollFlags to achieve the scroll effect. It must be enabled for any scroll effects to take into effect. This flag must be enabled along with enterAlways, enterAlwaysCollapsed, exitUntilCollapsed, or snap.
enterAlways: The view will become visible when scrolling up. This flag is useful in cases when scrolling from the bottom of a list and wanting to expose the Toolbar as soon as scrolling up takes place.
enterAlwaysCollapsed: Normally, when only enterAlways is used, the Toolbar will continue to expand as you scroll down.Assuming enterAlways is declared and you have specified a minHeight, you can also specify enterAlwaysCollapsed. When this setting is used, your view will only appear at this minimum height. Only when scrolling reaches to the top will the view expand to its full height
exitUntilCollapsed: When the scroll flag is set, scrolling down will normally cause the entire content to move.By specifying a minHeight and exitUntilCollapsed, the minimum height of the Toolbar will be reached before the rest of the content begins to scroll and exit from the screen
snap: Using this option will 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.
Code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/llBase"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbarContainer"
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="#dimen/_40sdp"
android:gravity="center"
android:theme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways">
<include
layout="#layout/top_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:id="#+id/rlMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
You need to use CoordinatorLayout to achieve what you want.
You could find all needed information in this tutorial.
I know it's old but I really tired from searching and trying a lot of solutions from here or from outside web pages
the problem is: when to invoke data from API to a Vertical RecyclerView it loads all data without any consideration to Pagination
which work successfully with the horizontal Recycler view
and without any scrolling or screen touch
NestedScroll View contain 2 Recycler in the following order
NestedScrollView as parent
HorizontalRecyclerView as child
VerticalRecyclerView as child
my XML file :
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.organizers_group.stadfm.Activities.NewsFeedHome"
tools:showIn="#layout/app_bar_news_feed_home">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nestedScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/_5dp"
android:paddingBottom="#dimen/_7dp">
<RelativeLayout
android:id="#+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<TextView
android:id="#+id/horizontalTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/trending_stories"
android:layout_marginStart="#dimen/_10dp"
android:paddingTop="#dimen/_10dp"
android:paddingBottom="#dimen/_10dp"
android:fontFamily="#font/avenir_heavy"
android:textColor="#color/trending_stories_color"
android:textSize="#dimen/_20sp"/>
<io.supercharge.shimmerlayout.ShimmerLayout
android:id="#+id/shimmer_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_below="#+id/horizontalTitle"
app:shimmer_animation_duration="1200">
<!-- Adding rows of placeholders -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="#layout/place_holder" />
<include layout="#layout/place_holder" />
<include layout="#layout/place_holder" />
</LinearLayout>
</io.supercharge.shimmerlayout.ShimmerLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/horizontalRecycler"
android:layout_width="match_parent"
android:layout_below="#+id/trending_story"
android:layout_height="wrap_content"
android:orientation="horizontal" />
<ProgressBar
android:id="#+id/pBLoading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="invisible"
android:layout_alignParentBottom="true"
style="?android:attr/progressBarStyleHorizontal" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="#+id/linearLayout2"
android:orientation="vertical"
android:layout_margin="#dimen/_8dp"
android:descendantFocusability="blocksDescendants"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout2"
app:layout_constraintVertical_bias="0.032"
app:layout_constraintVertical_weight="1">
<LinearLayout
android:id="#+id/storiesLayout"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_10dp"
android:paddingBottom="#dimen/_5dp"
android:text="#string/your_stories"
android:fontFamily="#font/avenir_heavy"
android:textColor="#color/stories_color"
android:textSize="#dimen/_20sp" />
<ImageView
android:id="#+id/moreStoriesImg"
android:layout_width="#dimen/_40dp"
android:layout_height="#dimen/_40dp"
android:src="#drawable/more"
android:layout_gravity="center"/>
</LinearLayout>
<io.supercharge.shimmerlayout.ShimmerLayout
android:id="#+id/shimmer_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/story_layout"
android:orientation="vertical"
app:shimmer_animation_duration="1200">
<!-- Adding placeholders -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="#layout/place_holder" />
<include layout="#layout/place_holder" />
</LinearLayout>
</io.supercharge.shimmerlayout.ShimmerLayout>
<!-- problem is with the following recycler-->
<android.support.v7.widget.RecyclerView
android:id="#+id/verticalRecycler"
android:layout_width="match_parent"
android:layout_below="#+id/story_layout"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
<ProgressBar
android:id="#+id/pBLoading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="invisible"
android:layout_alignParentBottom="true"
style="?android:attr/progressBarStyleHorizontal" />
</RelativeLayout>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
EndlessRecyclerViewScrollListener class (from stackOverFlow)
package com.organizers_group.stadfm.Adapters;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
public abstract class EndlessRecyclerViewScrollListener extends
RecyclerView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 5;
// The current offset index of data you have loaded
private int currentPage = 1;
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// Sets the starting page index
private int startingPageIndex = 1;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public int getLastVisibleItem(int[] lastVisibleItemPositions) {
int maxSize = 0;
for (int i = 0; i < lastVisibleItemPositions.length; i++) {
if (i == 0) {
maxSize = lastVisibleItemPositions[i];
}
else if (lastVisibleItemPositions[i] > maxSize) {
maxSize = lastVisibleItemPositions[i];
}
}
return maxSize;
}
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
#Override
public void onScrolled(RecyclerView view, int dx, int dy) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to the initial state
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) {
this.loading = true;
}
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
// threshold should reflect how many total columns there are too
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, totalItemCount, view);
loading = true;
}
}
// Call this method whenever performing new searches
public void resetState() {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = 0;
this.loading = true;
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view);
}
my activity :
RecyclerView horizontalRecyclerView = findViewById(R.id.horizontalRecycler);
horizontalRecyclerView.setHasFixedSize(true);
LinearLayoutManager horizontalLayoutManager = new LinearLayoutManager(this , LinearLayoutManager.HORIZONTAL , false);
horizontalRecyclerView.setLayoutManager(horizontalLayoutManager);
// get trending post
final int trendingPage = 1;
myCustomAdapter = new MyCustomAdapter( this , getPosts(Page));
horizontalRecyclerView.setAdapter(myCustomAdapter);
myCustomAdapter.notifyDataSetChanged();
EndlessRecyclerViewScrollListener scrollListener = new EndlessRecyclerViewScrollListener(horizontalLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
showProgressView(ProgressBar);
getPosts(page);
}
};
// Adds the scroll listener to RecyclerView
horizontalRecyclerView.addOnScrollListener(scrollListener);
// End Of horizontalRecyclerView
// Stories RecyclerView
RecyclerView verticalRecycler = findViewById(R.id.verticalRecycler);
verticalRecycler.setHasFixedSize(true);
verticalRecycler.setNestedScrollingEnabled(false);
LinearLayoutManager verticalLayoutManager = new LinearLayoutManager(this , LinearLayoutManager.VERTICAL , false);
verticalRecycler.setLayoutManager(verticalLayoutManager);
// get mixed posts
verticalAdapter = new VerticalAdapter( this , getStoriesPosts(1));
verticalRecycler.setAdapter(verticalAdapter);
verticalAdapter.notifyDataSetChanged();
EndlessRecyclerViewScrollListener mixedScrollListener = new EndlessRecyclerViewScrollListener(verticalLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
showProgressView(progressBar);
getStoriesPosts(page);
}
};
// Adds the scroll listener to RecyclerView
storiesRecyclerView.addOnScrollListener(mixedScrollListener);
// End Of Mixed Stories
please help me!
how to do pagination with that vertical RecyclerView?
any bit of help is very appreciated
Thanks in advance.
Update at 2021 Feb
Based on Android documentation:
Never add a RecyclerView or ListView to a scroll view. Doing so results in poor user interface performance and a poor user experience.
The best new way is to use MergeAdapter. It added to Recyclerview v1.2.0alpha. So add this dependency:
implementation "androidx.recyclerview:recyclerview:1.2.0-beta01"
If you want to put two Adapters in one recyclerView, follow this Guide:
then make an instance of MakeAdapter and pass your adapters on it then set it as RecyclerViewAdapter:
ConcatAdapter ca = new (firstAdapter, secondAdapter);
myRecyclerView.setAdapter(ca);
If you have a layout and Pagedlist, follow this Guide:
Then Make and Simple ViewHolder and put the first layout on it. Then make MergeAdapter then add your layout's adapter and then PagedList's adapter, then add adapter of PagedList:
ConcatAdapter ca = new ConcatAdapter();
ca.addAdaper(simpleAdapter);
ca.addAdapter(pagedListAdapter);
then set this mergeAdapter to recyclerView's adapter;
myRecyclerView.setAdapter(ca);
to solve this challenge I perform the following Steps:
1- for XML file or EndlessRecyclerViewScrollListener NO CHANGES
2- for my activity I delete EndlessRecyclerViewScrollListener for vertical Recycler and defined my NestedScrollListener instance then set OnScrollChangeListener as below:
boolean loading = true;
int pageNumber = 1;
NestedScrollView scroller = findViewById(R.id.nestedScroll);
if (scroller != null) {
scroller.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
if (scrollY > oldScrollY) {
Log.i(TAG, "Scroll DOWN");
}
if (scrollY < oldScrollY) {
Log.i(TAG, "Scroll UP");
}
if (scrollY == 0) {
Log.i(TAG, "TOP SCROLL");
}
if (scrollY == ( v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight() )) {
Log.i(TAG, "BOTTOM SCROLL");
// here where the trick is going
if (loading){
pageNumber++;
showProgressView(mixedProgressBar);
// calling from adapter addToExistingList(list)
// with the defined Adapter instance
verticalAdapter.addToExistingList(getPosts(pageNumber));
// reset the boolean(loading) to prevent
// auto loading data from APi
loading = false;
}
}
});
}
3- for VerticalAdapter, I add the following method :
public void addToExistingList(List<DataModel> dataModelList){
// update oldDataModelList with newer data from pagination
oldDataModelList.retainAll(dataModelList);
notifyItemRangeChanged(oldDataModelList.size()-1 , dataModelList.size());
}
4- for getPosts(pageNumber) on fetching data success re-assign the boolean(loading)
getPosts(pageNumber) is a method to invoke data from API
JsonArrayRequest arrayRequest = new JsonArrayRequest(Request.Method.GET,baseAPI,
response1 -> {
try {
// doing stuff to invoke your data
// re-assign loading variable to load again
loading = true;
} catch (JSONException e) {
e.printStackTrace();
}
I need to use recycleview inside scrollview . I use this but I've a problem , I need to use OnScrollListener with my recycleview for getting new data when user reaches the end of recyleview , this problem is ,it not being called when I use recyleview inside scrollview .
this is my code :
<ScrollView
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="170dp" />
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</ScrollView>
I've a frameLayout that returns my fragment and the fragment contains a recycleview .
this is my java code but it's just called once and not calling again when I scroll recyeleview :
ads.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.v("this","Scroll");
visibleItemCount = ads.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loadmore) {
if (totalItemCount > previousTotal) {
previousTotal = totalItemCount;
}
}
if ((totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
if (taskrunning != null && taskrunning == false && loadmore) {
loadmore = false;
page = page + 1;
new AsyncHttpTask(1).execute(url);
}
}
}
});
how can I solve this problem ?
I created recyclerview and header layout, when I scroll up recyclerview, the header layout should be disappeared according to the scrolling offset of recyclerview.
My layout xml file is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:showIn="#layout/activity_main"
tools:context=".MainActivity"
android:id="#+id/main_container">
<TextView android:layout_width="match_parent"
android:layout_height="50dp"
android:id="#+id/header"
android:text="Mao Minh Tri"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header"/>
</RelativeLayout>
and the implemented code when scrolling recyclerview
RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (originalHeight == 0) {
originalHeight = myrecyclerView.getHeight();
}
ViewGroup.LayoutParams lp = myrecyclerView.getLayoutParams();
calculateLocationAndProductStickerOffset();
textview.setTranslationY(-offset);
mainView.setTranslationY(-offset);
if ((offset < textview.getHeight() && dy > 0) || (offset > 0 && dy < 0)) {
offset += dy;
}
System.out.println("original height --> " + originalHeight);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
};
myrecyclerView.addOnScrollListener(scrollListener);
}
private void calculateLocationAndProductStickerOffset() {
if (offset > textview.getHeight()) {
offset = textview.getHeight();
} else if (offset < 0) {
offset = 0;
}
}
And my result:
Here the best way to use a header with recycleview without using RecyclerView.OnScrollListener
I think you don't need to do all of that.. you just need to change your parent layout from RelativeLayout to CoordinatorLayout which supports doing that by default.
Here's a good tutorial to do that:
https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout
I want to achieve a Google+ profile page-like effect (check the attached GIF)
What I have achieved
So far I have achieved:When you scrolling to bottom (drag up), the header image will shrink and the SlidingTabs will pin to below the ActionBar. Just like the first half of the GIF
However I was unable to do the reverse: when the RecyclerView reaches its first child, it stops sending the onScrolled event and header view cannot be expanded.
Related Files
Heres my layout file:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:animateLayoutChanges="true"
android:fitsSystemWindows="false"
tools:context=".ProfileActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/profile_header_background_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/header"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
tools:src="#drawable/ic_launcher" />
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="vertical">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar_actionbar_layout" />
<include
android:id="#+id/profile_bio_view"
layout="#layout/profile_header" />
</LinearLayout>
<SlidingTabLayout
android:id="#+id/profile_sliding_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header" />
<android.support.v4.view.ViewPager
android:id="#+id/profile_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_below="#+id/profile_sliding_tags" />
</RelativeLayout>
<include layout="#layout/drawer_navigation_layout" />
</android.support.v4.widget.DrawerLayout>
Inside the ViewPager's RecyclerView I did this:
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Bus.post(new ProfileScrolledEvent(recyclerView.getChildAt(0).getTop(), state, dy));
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
state = newState;
// intercept the touch event if scroll state=0 (IDLE)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
Bus.post(new ProfileScrolledEvent(recyclerView.getChildAt(0).getTop(), state, 0));
recyclerView.getParent().getParent().requestDisallowInterceptTouchEvent(true);
} else {
recyclerView.getParent().getParent().requestDisallowInterceptTouchEvent(false);
}
}
});
So that when the RecyclerView is scrolling I can post the pixels scrolled to the activity, and in my activity:
#Subscribe
public void onProfileScrolledEvent(ProfileScrolledEvent event) {
// FIXME: can scroll with shrink header, but the header will not expand as expected
int scrollState = event.getScrollState();
int pixels = event.getScrolledPixels();
int recyclerViewTop = event.getRecyclerViewTop();
if (pixels == 0 && scrollState == 0) {
//TODO intercept the touch event
shouldIntercept = true;
} else {
shouldIntercept = false;
scrollProfile(recyclerViewTop);
}
LogUtil.debug("Bus event. top: " + recyclerViewTop + " state: " + scrollState + " pixels: " + pixels);
}
private void scrollProfile(int pixels) {
ViewGroup.LayoutParams headerParams = profileBioView.getLayoutParams();
headerParams.height = profileBioView.getHeight() + pixels / 2;
currentHeaderHeight = headerParams.height;
LogUtil.debug("currentHeaderHeight: " + currentHeaderHeight +
"\n profileBioView.getHeight: " + profileBioView.getHeight() +
"\n background.getHeight: " + headerBackground.getHeight());
ViewGroup.LayoutParams imageParams = headerBackground.getLayoutParams();
imageParams.height = headerParams.height;
if (headerParams.height <= 0) {
headerBackground.setVisibility(View.INVISIBLE);
} else {
headerBackground.setVisibility(View.VISIBLE);
slidingTabLayout.setTranslationY(pixels / 2);
if (headerParams.height > origHeaderHeight) {
headerParams.height = origHeaderHeight;
imageParams.height = origHeaderHeight;
}
profileBioView.setLayoutParams(headerParams);
headerBackground.setLayoutParams(imageParams);
}
}
Question
The problem is, when the RecyclerView reaches its first child, the onScrolled event stops, the ScrollState becomes IDLE. At this point, I want to notify the parent activity to intercept the TouchEvent and carry on moving the header view. However when I tried to register a GestureListener inside the activity, it simply not get called.
So is there any better way to do this? Or is it possible to intercept a child's TouchEvent under a certain condition?
FYI: I used Otto Bus to post messages, check here: http://square.github.io/otto/