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();
}
Related
My HomeBuyersActivity consists of multiple recyclerviews (ex. popular stores, popular products, discover products, discover store and etc.) which are aligned vertically but their item layouts are aligned horizontally. So when I open the activity, the process of retrieving the data is too long because it was loading all the files at the same time. Here is the sample code of my XML file:
XML: (Note: all of the included layouts consists of recyclerviews)
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/a ndroid"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/defaultBackground"
tools:context=".Activity.HomeBuyersActivity">
<androidx.core.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp">
<include
layout="#layout/popular_store_layout"
android:visibility="visible" />
<include
layout="#layout/popular_products_layout"
android:visibility="visible" />
<include
layout="#layout/discover_store_layout"
android:visibility="visible" />
<include
layout="#layout/discover_products_layout"
android:visibility="visible" />
//.... and more recyclerviews
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
And in HomeBuyersActivity I am populating those recyclerviews with the data that are retrieved from firestore. The only solution that I came out with is to load only the layout that is/are visible to the screen but I don't know how to do it. Is there a way to achieve that process? If not, Is there any better solution or other way around?
You said it takes a lot time to load data .To fix that one thing you can do is to add pagination to your query rather than messing with recyclerview's core functionalities.
Read more at : https://firebase.google.com/docs/firestore/query-data/query-cursors
Query firstPage = cities.orderBy("population").limit(25);
limit is what you need and you can always load more data when recyclerview scroll reaches to the end.
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
{
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisibleItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
loading = false;
if (adapter.countOfShowing < adapter.allChallenges.size()) {
Log.e("...", "Last Item Wow !");
adapter.increaseCountOfShowing();
adapter.notifyDataSetChanged();
}
loading = true;
//Do pagination.. i.e. fetch new data
}
}
}
}
});
ref: https://stackoverflow.com/a/45909144/3995126
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);
I am using recylerview and gridlayout manager with cardviews for each row, my row view(childview) is not responsive at all.
I want to show 15 cardviews in such a way that in portrait mode all my 15 childview should be visible and my recyclerview should not be scrollable whereas in landscape mode it should act vise versa( should be scrollable)
I have tried many soultions suggested on SO but nothing seems to be working.
current behaviour on different screen sizes are as follows
In the above attached screen shot ,the 3rd column, 4th and 5th row are not visible
In the above given screen my ui fits perfectly in portrait mode but in landscape i can't see all the cardviews.
in the screenshot attached above ,5th row is not visible and in the landscape mode there are some responsivness errors.
cardview.xml
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cardview="http://schemas.android.com/apk/res-auto"
android:layout_width="127dp"
android:layout_height="118dp"
android:layout_margin="5dp"
cardview:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/mReminder_Image_Id"
android:layout_width="match_parent"
android:layout_height="90dp"
android:scaleType="fitXY"
android:background="#ffffff"/>
<TextView
android:id="#+id/mReminder_Text_Id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="#2d2d2d"
android:textSize="13sp"
android:text="Reminder texts"/>
</LinearLayout>
</android.support.v7.widget.CardView>
fragment_reminders.xml
<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="match_parent"
android:orientation="vertical"
tools:context=".Fragments.Reminders">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reminders"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="#color/tab_background"
android:layout_gravity="center" />
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView_id"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
Can anyone guide me to solve this .
Thanks .
you can use this:
recyclerView.setLayoutManager(new RecyclerView.GridLayoutManager(this, span_count)
You could have a
res/values/ints.xml file with <integer> elements, giving the integer a name (name attribute) and value (text of the <integer> node). You could also have res/values-w600dp/ints.xml or res/values-land or other variations of the resource, where you provide
different values to use for different screen sizes. Then, at runtime, call
getResources().getInteger() to retrieve the correct value of the resource to use
for the current device, and use that in your GridLayoutManager constructor. Now,
you are in control over how many columns there are, by controlling how many spans
are supplied to the constructor.
https://developer.android.com/training/multiscreen/screensizes
Another approach, suggested by Chiu-Ki Chan, is to create a subclass of
RecyclerView, on which you provide a custom attribute for a desired approximate
column width. Then, in your subclass’ onMeasure() method, you can calculate the
number of spans to use to give you the desired column width.
https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html#GridLayoutManager(android.content.Context,%20int)
https://developer.android.com/reference/android/support/v7/widget/RecyclerView#setlayoutmanager
create a class as follows:
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class EqualSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int spacing;
private int displayMode;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int GRID = 2;
public EqualSpacingItemDecoration(int spacing) {
this(spacing, -1);
}
public EqualSpacingItemDecoration(int spacing, int displayMode) {
this.spacing = spacing;
this.displayMode = displayMode;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildViewHolder(view).getAdapterPosition();
int itemCount = state.getItemCount();
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
setSpacingForDirection(outRect, layoutManager, position, itemCount);
}
private void setSpacingForDirection(Rect outRect,
RecyclerView.LayoutManager layoutManager,
int position,
int itemCount) {
// Resolve display mode automatically
if (displayMode == -1) {
displayMode = resolveDisplayMode(layoutManager);
}
switch (displayMode) {
case HORIZONTAL:
outRect.left = spacing;
outRect.right = position == itemCount - 1 ? spacing : 0;
outRect.top = spacing;
outRect.bottom = spacing;
break;
case VERTICAL:
outRect.left = spacing;
outRect.right = spacing;
outRect.top = spacing;
outRect.bottom = position == itemCount - 1 ? spacing : 0;
break;
case GRID:
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
int cols = gridLayoutManager.getSpanCount();
int rows = itemCount / cols;
outRect.left = spacing;
outRect.right = position % cols == cols - 1 ? spacing : 0;
outRect.top = spacing;
outRect.bottom = position / cols == rows - 1 ? spacing : 0;
}
break;
}
}
private int resolveDisplayMode(RecyclerView.LayoutManager layoutManager) {
if (layoutManager instanceof GridLayoutManager) return GRID;
if (layoutManager.canScrollHorizontally()) return HORIZONTAL;
return VERTICAL;
}
}
and for using it with your recycler view:
1)for grid view:
recyclerView.addItemDecoration(new EqualSpacingItemDecoration(<sizeofpixels>, EqualSpacingItemDecoration.GRID));
2)for vertical view:
recyclerView.addItemDecoration(new EqualSpacingItemDecoration(<sizeofpixels>, EqualSpacingItemDecoration.VERTICAL));
3)for horizontal view:
recyclerView.addItemDecoration(new EqualSpacingItemDecoration(<sizeofpixels>, EqualSpacingItemDecoration.HORIZONTAL));
hope this helps you.
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'm trying to create a dynamic RecyclerView layout. I am using a GridLayoutManager with three columns.
I need to wrap each grid item and center the columns (like attached).
I have tried a StaggeredGridLayout, I have tried a WrapGridLayoutManager but neither of these worked.
Here is my RecyclerView:
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/categories_grid"
android:layout_marginTop="#dimen/feed_item_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
and my RecyclerView item:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:background="#drawable/first_time_category_unselected"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="#+id/category_name"
android:layout_marginLeft="#dimen/feed_item_margin"
android:layout_gravity="center_vertical"
android:textColor="#color/black_colour"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/category_status_icon"
android:layout_gravity="center_vertical"
android:background="#drawable/icon_follow"
android:layout_marginLeft="#dimen/feed_item_margin"
android:layout_marginRight="#dimen/feed_item_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
This is the decoration I'm using to implement grid spacing:
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int halfSpace;
public SpacesItemDecoration(int space) {
this.halfSpace = space / 2;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getPaddingLeft() != halfSpace) {
parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
parent.setClipToPadding(false);
}
outRect.top = halfSpace;
outRect.bottom = halfSpace;
outRect.left = halfSpace;
outRect.right = halfSpace;
}
}
This is what I'm trying to achieve:
This is what I am getting:
If anyone can help on this I'd greatly appreciate it
You can use Staggered Grid Layout Manager
as
StagaggeredGridLayoutManager = new StaggeredGridLayoutManager(3, LinearLayoutManager.HORIZONTAL );
recyclerView.setLayoutManager(gaggeredGridLayoutManager);
Here is Link for reference
Use this in recyclerView you could not arrange as you shown
<cuneyt.example.com.tagview.Tag.TagView
android:id="#+id/tag_group"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
Download repo from GIT https://github.com/Cutta/TagView
TagView tagGroup = (TagView)findviewById(R.id.tag_view);
//You can add one tag
tagGroup.addTag(Tag tag);
//You can add multiple tag via ArrayList
tagGroup.addTags(ArrayList tags);
//Via string array
addTags(String[] tags);
//set click listener
tagGroup.setOnTagClickListener(new OnTagClickListener() {
#Override
public void onTagClick(Tag tag, int position) {
}
});
//set delete listener
tagGroup.setOnTagDeleteListener(new OnTagDeleteListener() {
#Override
public void onTagDeleted(final TagView view, final Tag tag, final int position) {
}
});
How do I make WRAP_CONTENT work on a RecyclerView