I am trying to create a list to scroll on either direction horizonally. Based on the solutions on How do I create a circular (endless) RecyclerView? I was able to make it go horizontally to the right endlessly but that does not work if I go on the left.
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
firstVisibleItemPos = ListLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItemPos != 0 && firstVisibleItemPos % items.size() == 0) {
recyclerView.getLayoutManager().scrollToPosition(firstVisibleItemPos %
items.size());
}else if(firstVisibleItemPos == 0 && items.size() > 0){
int newPos = items.size() / 2;
recyclerView.getLayoutManager().scrollToPosition(newPos);
}
}
#Override
public int getItemCount() {
return Items== null ? 0 : Items.size() * 2;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
position = position % categoryViewItems.size();
... some code for displaying here
}
I tried using Integer.MAX_VALUE but that resulted in wrong positions when I click on the item.
Is there a way that i go on the left 0...n-5,n-4, n-3,n-2, n-1,n, 0,1,2,3,4,5,...n
****************EDIT ************************
Tried
#Override
public int getItemCount() {
return Items== null ? 0 : Integer.MAX_VALUE;
}
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
firstVisibleItemPos =
ListLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItemPos != 0 && firstVisibleItemPos % items.size() == 0)
{
recyclerView.getLayoutManager().scrollToPosition(Integer.MAX_VALUE / 2);
}else if(firstVisibleItemPos == 0 && items.size() > 0){
recyclerView.getLayoutManager().scrollToPosition(Integer.MAX_VALUE / 2);
}
}
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Item selectedItem = Items.get(getAdapterPosition());
currentlySelectedItem = selectedItem ;
notifyDataSetChanged();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
} catch (Exception exc) {
exc.printStackTrace();
}
}
});
}
getAdapterPosition() is returning the wrong position, onBindViewHolder() is still usign the same logic for position.
I was able to solve this by adding onClickListner in onBindViewHolder(). This returned the right position when compared to in viewholder and using getAbsoluteposition().
Related
I am doing app where I have to make my half screen visible and half sreen Dull. When I start Scrolling, First View should be clear and else in Hazy Manner. as soon as I scroll them and first position gone from screen Second Position Item must be Clear and others in Hazy means dull. How can I do ?
What I tried..
My Adapter
#Override
public void onBindViewHolder(PageCircleIndiAdapter.ViewHolder holder, int position) {
final PageModels pageModels = pageList.get(position);
if (pageList.get(position) != null) {
holder.imageView.setImageResource(pageModels.resourceId);
if (position == 0) {
holder.imageView.setAlpha(1f);
} else if (position == pageList.size() - 1) {
holder.imageView.setAlpha(1f);
pageCircleIndicator.changeIndicator(position);
} else if (position > firstVisible && position < lastVisible) {
pageCircleIndicator.changeIndicator(position);
holder.imageView.setAlpha(0.2f);
}
if (position == pageList.size() - 1) {
pageCircleIndicator.changeIndicator(position);
} else {
holder.imageView.setAlpha(0.2f);
pageCircleIndicator.changeIndicator(position);
}
}
}
My ScrollView on MainActivity
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstVisible = manager.findFirstVisibleItemPosition();
int lastVisible = manager.findLastVisibleItemPosition();
Log.i("TAG", "onScrolled: " + firstVisible);
Log.i("TAG", "Last Index: " + lastVisible);
pageAdapter.changeItem(firstVisible, lastVisible);
}
});
createIndicator();
pageAdapter.notifyDataSetChanged();
}
I have a RecyclerView with GridLayoutManager , i want to find inside the method getItemOffsets of the Class RecyclerView.ItemDecoration if the user is scrolling up or down . Below is my code inside the class GridDividerDecoration where i draw borders between the items.
public class GridDividerDecorations extends RecyclerView.ItemDecoration {
private int mInsets;
List<Integer> itemsHeaderPos= new ArrayList<>();
List<Integer> itemsPos= new ArrayList<>();
List<GadgetItem> mList = new ArrayList<>();
int lastItem;
int itemPosition, itemposition2 = 0;
public GridDividerDecorations(Context context,List<GadgetItem> mList ) {
this.mList = mList;
mInsets = 6;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if ((parent.getAdapter().getItemViewType(itemPosition) == 0))
itemsHeaderPos.add(itemPosition);
if((parent.getAdapter().getItemViewType(itemPosition) != 0))
itemsPos.add(itemPosition);
outRect.top = mInsets;
GridLayoutManager layoutManager = (GridLayoutManager)parent.getLayoutManager();
if(itemPosition == layoutManager.findLastVisibleItemPosition())
outRect.right = mInsets;
if (itemPosition % 2 == 0 && itemsHeaderPos.get(itemsHeaderPos.size() - 1) % 2 == 0) {
if (parent.getAdapter().getItemViewType(itemPosition) != 0)
outRect.left = mInsets;
} else if (itemPosition % 2 == 0 && itemsHeaderPos.get(itemsHeaderPos.size() - 1) % 2 != 0) {
if (parent.getAdapter().getItemViewType(itemPosition) != 0) {
outRect.right = mInsets;
}
}
}
}
The thing is that when I scroll up the dividers are painted upside down, so finding if the user scroll ups i can revert my implementation. Thank you!
You can determine if scrolled up or down with an OnScrollChangeListener:
recycler.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if(oldScrollY - scrollY > 0) {
// do stuff
}
else {
// do stuff
}
}
});
I'm new to Android. My requirement is to load extra data & set to the list view, when scroll reaches to the bottom. I am able to call next data but my previous data is hiding. How to correct this?
listView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
// TODO Auto-generated method stub
}
#Override
public void onScroll(AbsListView view,
int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
// TODO Auto-generated method stub
if (listView.getLastVisiblePosition() == listView
.getAdapter().getCount() - 1
&& listView.getChildAt(
listView.getChildCount() - 1)
.getBottom() <= listView
.getHeight()) {
// scroll end reached
if (nextCall == null || nextCall == ""
|| nextCall.equals("null")
|| nextCall.equals("")) {
} else {
hostname=nextCall;
new ArticlesList().execute();
}
// Write your code here
}else{
}
}
});
dialog.dismiss();
} else {
Toast.makeText(getActivity(), "Went wrong",
Toast.LENGTH_LONG).show();
dialog.dismiss();
}
visit this which is discribe how to do pagination in listview. PagingListView
What you need is an endless scroll Listener, please take a look at this: https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
just add this project to yours and use it like this:
yourListView.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
... your asynchTask
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
super.onScrollStateChanged(view, scrollState);
}
});
In listView adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (position == items.size() - 1)
{
items.add("new data1");
items.add("new data2");
notificationDataSetChanged();
}
//inject your view here
}
You lose your data, because you are overwriting a link to it. You should add data, not replace it.
I solved the same problem using following code snippet.
private int lastVisibleItem; private LinearLayoutManager linearLayoutManager; private int lastId; // get the last id of your post after first time load data from server. private int flag = 0;
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView_news.setLayoutManager(linearLayoutManager);
recyclerView_news.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);
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
new Handler().post(new Runnable() {
#Override
public void run() {
if (list_news.size() - 1 == lastVisibleItem) {
if (flag == 0) {
flag = 1;
getMoreData(lastId); // pass lastId to load next posts.
}
} else if (list_news.size() - 1 != lastVisibleItem) {
flag = 0;
}
}
});
}
});
Hope this will help. Thanks.
I never seen something like that before but from last few days I am experiencing very peculiar behavior of the Listview and until now I am not been able to isolate the issue.
I only paste the code which I think is necessary and later I will tell you my problem.
/* tell adapter that data is done and stop the more loading progress bar*/
public void setDataChanged(boolean type)
{
isLoadingData = false;
notifyDataSetChanged();
}
/* If loading is going on size of the adapter will increase to show the additional progress bar*/
#Override
public int getCount() {
int size = friendsModels.size();
if (isLoadingData) {
size += 1;
}
Log.i("size", String.valueOf(size));//to check size
return size;
}
/* set loading true and page number of the data items*/
public void setLoadingData(boolean isLoadingData, int page) {
this.isLoadingData = isLoadingData;
this.page = page;
notifyDataSetChanged();
}
/* MAX_ITEM number of item returning from rest webservice per page*/
#Override
public int getItemViewType(int position) {
if(isLoadingData && position%MAX_ITEM==0 && position>0)
{
if(position/MAX_ITEM==page+1)
return 1;
}
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.e("getView", "getView");
EventHolder eventHolder;
int type = getItemViewType(position);
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(convertView==null){
eventHolder = new EventHolder();
if(type==0)
{
convertView = li.inflate(R.layout.friends_list_items, parent,false);
eventHolder.name = (TextView)convertView.findViewById(R.id.textview_friend_name);
convertView.setTag(eventHolder);
}
else if(type==1)
{
convertView = li.inflate(R.layout.progress_dialog, parent,false);
eventHolder.progress = (RelativeLayout)convertView.findViewById(R.id.progress_layout);
convertView.setTag(eventHolder);
}
}
else
{
eventHolder = (EventHolder) convertView.getTag();
if(type==0)
{
setFriends(eventHolder, position);
}
}
return convertView;
}
Now onScroll method-
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem + visibleItemCount >= totalItemCount && !loading && totalItemCount%6==0 && totalItemCount>0 && NetworkUtil.isNetworkAvailable(activity))
{
loading = true;
friendsAdapter.setLoadingData(true,pageNo);
ControllerRequests.getPeople(FragmentClass.this, ++pageNo, search.getText().toString());
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
Though everything is working fine when there are like 5 or more items but as the item size decreases let's say 1 or 2 then sometimes the getView method don't get called though log info is showing me getCount = 1 or 2 but getView just don't get called. There is no pattern, I mean sometimes 5 times getView get called it works fine then suddenly not and like that.
This is a strange check:
if(firstVisibleItem + visibleItemCount >= totalItemCount && !loading &&
totalItemCount%6==0 && totalItemCount>0 &&
NetworkUtil.isNetworkAvailable(activity))
I am referring to:
totalItemCount % 6 == 0
So, unless the total number of items will always be a multiple of 6, this check will prevent friendsAdapter.setLoadingData(true,pageNo); from being called. That's why the statement notifyDataSetChanged(); that resides inside setLoadingData(boolean, int) will not be executed whenever totalItemCount % 6 != 0.
Edit:
I also cannot think of a situation where this will be true:
firstVisibleItem + visibleItemCount > totalItemCount
You can go with the following to check if the user has reached the end of the list:
firstVisibleItem + visibleItemCount == totalItemCount
I want to determine if my Gridview is scrolled to its top.
Right now I'm using getChildAt(0).getTop() to do this. I save the value of getChildAt(0).getTop() on first draw and compare to getChildAt(0).getTop() on subsequent draws .
However, this seems hacky and seems to sometimes give me incorrect results.
Any better ideas?
Try using the onScrollListener
setOnScrollListener(this);
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(firstVisibleItem == 0){
//do stuff here
}
}
The getChildAt(0) returns you the first visible item of the GridView and I guess that it's not what you want.
If you use yourGridView.getFirstVisiblePosition() method it will return the first visible position your data adapter, and that is what you want.
Hope this can help, it works for me, good luck.
yourGridView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(SCROLL_STATE_IDLE == scrollState) {
View view = view.getChildAt(0);
if(view != null) {
float y = view.getY();
Log.d("Tag", "first view Y is " + y);
if(y == 0) {
// do what you want
}
}
}
}
This's my answer:
mLayoutManager = new GridLayoutManager(getActivity(), 2);
mListRV= (RecyclerView).findViewById(R.id.list_rv);
mListRV.setLayoutManager(mLayoutManager);
mListRV.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
View v = mLayoutManager.getChildAt(0);
int offsetTop = v.getTop();
int offsetBottom = v.getBottom();
int height = (offsetBottom - offsetTop);
if(offsetTop >= -height/2) {
mListRV.smoothScrollBy(0, offsetTop);
} else {
mListRV.smoothScrollBy(0, height + offsetTop);
}
}
}
});