I am facing an issue while adding the horizontal recyclerview inside vertical recyclerview in 2nd position of recyclerview. The data is loaded in vertical recyclerview using arraylist. But the 2nd position data is not getting displayed in vertical recycler view in third position.How to achieve that?
#Override
public int getItemCount() {
if (mWaveLineResponseList != null && mWaveLineResponseList.size() > 0) {
return mWaveLineResponseList.size();
} else {
return 1;
}
}
#Override
public int getItemViewType(int position) {
if (position == 2) {
viewPosition = 3;
} else {
viewPosition = (position == mWaveLineResponseList.size() - 1 && isLoadingAdded) ? VIEW_TYPE_PROGRESS : VIEW_TYPE_NORMAL;
}
return viewPosition;
}
Related
I have RecyclerView with 2 columns. What I want is to show last item in center if number of items in list is odd. Something like this
I have tried implementing all the so threads from here https://www.google.com/search?client=firefox-b-d&q=show+last+item+in+recyclerview+center+horizontal+android
I have used below code to set layout manager
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (mLangInfos.size() % 2 == 0)
return 1;
else {
if (position == mLangInfos.size()-1)
return 2;
else
return 1;
}
}
});
recyclerView.setLayoutManager(gridLayoutManager);
But what this does is it shows last item in full width, see below image.
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().
I have a RecyclerView with vertical orientation, each item of list consist of HorizontalScrollView in brief it's some kind of table with scrollable rows(check pic below)
When I scroll one of the horizontal view all others views should be also scrolled
What I already done:
private int scrollDistance;
#Override
public void onBindViewHolder(RecyclerView.Holder holder, int position) {
holder.binding.scrollView.post(() -> holder.binding.scrollView.scrollTo(scrollDistance, 0));
holder.binding.scrollView.setChangeListener(dx -> {
for (int i = layoutManager.findFirstVisibleItemPosition(); i <= layoutManager.findLastVisibleItemPosition(); i++) {
View view = layoutManager.findViewByPosition(i);
if (view == null) {
continue;
}
HorizontalScrollView scrollView = (HorizontalScrollView) view.findViewById(R.id.scrollView);
if (scrollView != null) {
scrollView.scrollTo(dx, 0);
}
}
scrollDistance = dx;
});
}
It works but when I start scroll down or up sometimes happen that HorizontalScrollView keeps old position.
Question: How I can synchronize all views at the same position?
Thanks in advance!
I have a problem in listview. If I scroll list, all is good. But if I click on checkbox, header disappears. I checked, notifyOfChange() not started. I think this is due to the drawing of view. Who knows how to make the header is drawn in the last instance.
I use the following code:
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//the listview has only few children (of course according to the height of each child) who are visible
for(int i=0; i < list.getChildCount(); i++)
{
View child = list.getChildAt(i);
MuscleViewHolder holder = (MuscleViewHolder) child.getTag();
//if the view is the first item at the top we will do some processing
if(i == 0)
{
boolean isAtBottom = child.getHeight() <= holder.headerLayout.getBottom();
int offset = holder.previousTop - child.getTop();
if(!(isAtBottom && offset > 0))
{
holder.previousTop = child.getTop();
holder.headerLayout.offsetTopAndBottom(offset);
holder.headerLayout.invalidate();
}
} //if the view is not the first item it "may" need some correction because of view re-use
else if (holder.headerLayout.getTop() != 0)
{
int offset = -1 * holder.headerLayout.getTop();
holder.headerLayout.offsetTopAndBottom(offset);
holder.previousTop = 0;
holder.headerLayout.invalidate();
}
}
}
The problem is solved. I replace the code to the following
if(!(isAtBottom && offset > 0)) {
holder.setPreviousTop(child.getTop());
if(itNotScroll){
holder.getHeaderLayout().offsetTopAndBottom(-holder.getPreviousTop());
itNotScroll = false;
} else {
holder.getHeaderLayout().offsetTopAndBottom(offset);
}
holder.getHeaderLayout().invalidate();
}
And yet, I did so, so that you can open only one element in expaned listview
update
Basically, bbrakenhoff has answered my question but there is just one more thing left to fix. How can I update the contents of my EndlessFeedAdapter (mEndlsFidAdptr)? I need to clear the item and then reload. I'm using the CWAC EndlessAdapater. Is there a trick to clear the contents or would it be easier to just program a method? After this is done the scroll position should be maintaind.
I am getting data from a server and updating my EndlessFeedAdapter when content changes. Each time I am updating my adapter and reloading content. The problem is that after reloading my list jumps right back to the top as my scroll position is not maintained. I have tried setSelection and setSelectionFromTop extensively, but without positive results.
How do I maintain scroll position after the adapter has been updated?
I have been going through the forums searching for an answer but nothing seems to be working.
I have tried all these: Maintain/Save/Restore scroll position when returning to a ListView
This didn't work:
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// restore index and position
mList.setSelectionFromTop(index, top);
Nor this:
// Save ListView state
Parcelable state = listView.onSaveInstanceState();
// Set new items
listView.setAdapter(adapter);
// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);
Nor the other solutions such as setting up a runnable or setting the scrollPositionY. Setting notifyDataChanged didn't work as I am loading from different lists.
My code:
private void showFeed() {
if (mFeedActivity.mInFeed) {
mQuickReturnView.setVisibility(View.VISIBLE);
} else {
mQuickReturnView.setVisibility(View.GONE);
}
Activity actvt= getActivity();
if (actvt == null || mFeedListView == null) return;
actvt.invalidateOptionsMenu();
mFeedListView.setVisibility(View.VISIBLE);
//updated with help from response
if (mAdapter == null){
mAdapter = new FeedAdapter(actvt, 0, mFeed.getItems().getFeedItemList(), this);
} else {
mAdapter.clear();
mAdapter.addAll(mFeed.getItems().getFeedItemList());
mAdapter.notifyDataSetChanged();
}
mEndlsFidAdptr = new EndlessFeedAdapter(actvt, mAdapter, R.layout.progress_row, mFeed.isShowMoreBar(),
mEndlsFidAdptr.setRunInBackground(false);
//Parcelable state = mFeedListView.onSaveInstanceState();
mFeedListView.setAdapter(mEndlsFidAdptr);
//mFeedListView.onRestoreInstanceState(state);
mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);
if(!(mFeedScope.equalsIgnoreCase(FeedScope.BOOKMARKS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.DOCUMENT.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.NOTIFICATIONS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.RECEIVED_TASKS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.SEND_TASKS.xmlValue()))) {
mFeedListView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
mFeedListView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCanShowHide = scrollState == SCROLL_STATE_FLING;
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View v = mFeedListView.getChildAt(0);
//View v = null;
if(!mFeedActivity.mInFeed || v == null)
return;
int top = v.getTop();
if(mIsAnimating) {
mVisibleItemOffset = top;
mFirstVisibleItem = firstVisibleItem;
return;
}
boolean hide = false;
boolean show = false;
float stickyHeight = getResources().getDimension(R.dimen.sticky_height);
if(firstVisibleItem == mFirstVisibleItem) {
if((top + stickyHeight) < mVisibleItemOffset) {
// Content scrolled down
// if shown then hide quickactionview
if(mQuickReturnShown) {
hide = true;
}
} else if (top > mVisibleItemOffset) {
// Content scrolled up
// if hidden then show quickactionview
if(!mQuickReturnShown) {
show = true;
}
}
} else if(firstVisibleItem > mFirstVisibleItem) {
// Content scrolled down
// if shown then hide quickactionview
if(mQuickReturnShown) {
hide = true;
}
} else if (firstVisibleItem < mFirstVisibleItem) {
// Content scrolled up
// if hidden then show quickactionview
if(!mQuickReturnShown) {
show = true;
}
}
if((show && mCanShowHide) || (top == 0 && !mQuickReturnShown)) {
mTranslateAnimation = new TranslateAnimation(0, 0, -mQuickReturnHeight, 0);
mTranslateAnimation.setDuration(DURATION_MILLIS);
mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
mIsAnimating = true;
}
#Override
public void onAnimationEnd(Animation animation) {
mIsAnimating = false;
mQuickReturnShown = true;
mQuickReturnView.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mQuickReturnView.startAnimation(mTranslateAnimation);
}
if(hide) {
mTranslateAnimation = new TranslateAnimation(0, 0, 0, -mQuickReturnHeight);
mTranslateAnimation.setDuration(DURATION_MILLIS);
mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
mIsAnimating = true;
}
#Override
public void onAnimationEnd(Animation animation) {
mIsAnimating = false;
mQuickReturnShown = false;
mQuickReturnView.setVisibility(View.GONE);
}
#Override
public void onAnimationRepeat(Animation animation) { }
});
mQuickReturnView.startAnimation(mTranslateAnimation);
}
mVisibleItemOffset = top;
mFirstVisibleItem = firstVisibleItem;
}
});
} else {
mFeedListView.setOnScrollListener(null);
}
mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);
//mFeedListView.scrollTo(mCurrentX,mCurrentY);
if(mFeed.getItems().getFeedItemList().size() == 0) {
mEmptyFeedView.setVisibility(View.VISIBLE);
}
}
Are you calling the method showFeed() everytime you received new data? If yes, then maybe you could try to refill the adapter instead of assigning a new one every time.
I don't know exactly what you are doing in your adapter, so I'll show you how I did it in one of my apps.
In my Activity/Fragment I do this when I want to update the list with new items:
private void refreshCalendar(ArrayList<CalendarDay> newCalendar) {
if (mAdapter == null) {
mAdapter = new CalendarAdapter(getActivity(), newCalendar);
mExpandableListView.setAdapter(mAdapter);
}
else {
mAdapter.refill(newCalendar);
}
restoreInstanceState();
}
And in the adapter:
public void refill(ArrayList<CalendarDay> newCalendar) {
mCalendar.clear();
mCalendar.addAll(newCalendar);
notifyDataSetChanged();
}
Maybe you could try and remove this line?
mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);
Edit: You are using this line twice in your code.
Edit: In the code in your question you are only refreshing mAdapter and not mEndlsFidAdptr . That one is still assigned a new one. Everytime you assign a new adapter to you ListView it scrolls back to the top.
So the solution wasn't the logical place where I was looking. Thanks a lot to bbrakenhoff for pointing me in the right direction!
My class showFeed() was called from another class called downloadFeed() my scroll position wasn't maintained because downloadFeed() was only loading 5 items when it refreshed, hence even if I maintained the correct scroll position it was not visible.
Although it may be a long shot if someone else has this problem - to fix simply create a variable to hold the total size of your scrollable list when the user performs an onClick event. Then when downloadFeed() is called again, there are more items to download instead the default 5. Then the scroll position is able to be maintained as the visible items are now present.
I ended up using mFeedListView.setSelectionFromTop(firstVisibleItem, positionOffset)