Reputation: 13
Probably this is the most common question regarding Android RecyclerView in stackoverflow and yet I could not find any suitable solution anywhere which fulfils my requirement.
I am using Paging Library with Room Database and Retrofit to populate contents in a Recyclerview.There are two VIEW_TYPE; One is the actual data in a cardview and another is a progressbar layout which shows up at bottom of Recyclerview when API is called to fetch next set of data. Each card view in the list is fairly complex holding image and texts.
Everything works fine till I start scroll up when contents get messed up. To be precise, one textview needs to be displayed based on another textView’s measured height. And the measured height is not coming properly after I scroll down and up. Image Screenshot attached below
There are 2 solutions I have found almost everyone suggested.
override getItemViewType(int position) in the adapter and return the position
~ I can't use this solution as I have to keep 2 VIEW_TYPES. My getItemViewType code is as below :
public int getItemViewType(int position) {
if (hasExtraRow() && position == getItemCount() - 1) {
return R.layout.item_network_state;
} else {
return R.layout.card_post_timeline;
}
}
Use setIsRecyclable(false) in ViewHolder
~ If I use this solution it solves my problem but I don't want to use this as this defeats the whole purpose of Recyclerview and it will badly affect performance when there will be large data set.
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == R.layout.card_post_timeline) {
View view = layoutInflater.inflate(R.layout.card_post_timeline, parent, false);
TimelinePostViewHolder viewHolder = new TimelinePostViewHolder(view, context,optionsSelected );
return viewHolder;
} else if (viewType == R.layout.item_network_state) {
View view = layoutInflater.inflate(R.layout.item_network_state, parent, false);
return new NetworkStateItemViewHolder(view);
} else {
throw new IllegalArgumentException("unknown view type");
}
}
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case R.layout.card_post_timeline:
((TimelinePostViewHolder) holder).bindTo(getItem(position)); // Data binding happens here
break;
case R.layout.item_network_state:
((NetworkStateItemViewHolder) holder).bindView(networkState);
break;
}
}`
What's the alternative we can use to resolve this age-old Recyclerview problem ?
Only problem is that "Show More" textview visibility which is getting calculated by postBody textview measured height . After scrolling down and then up, measured height of Textview always coming same irrespective of the text content.
Logic for the same as below:
private void renderPostContent(Post post) {
tvPostBody.fromHtml(post.getPostContent());
Log.d(StringConstants.LOG_TAG, tvPostBody.getText().toString());
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(IntegerConstants.SCREEN_WIDTH, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
tvPostBody.measure(widthMeasureSpec, heightMeasureSpec);
int measuredTextViewHeight = tvPostBody.getMeasuredHeight();
Log.d(StringConstants.LOG_TAG, "list position - " + getAdapterPosition() + " measuredHeight - " + measuredTextViewHeight);
if (measuredTextViewHeight > IntegerConstants.SCREEN_WIDTH) {
tvPostBody.setMaxHeight(IntegerConstants.SCREEN_WIDTH);
tvShowMore.setVisibility(View.VISIBLE);
// setIsRecyclable(false);
Log.d(StringConstants.LOG_TAG, "ShowMore visibile");
} else {
tvPostBody.setMaxHeight(IntegerConstants.SCREEN_WIDTH);
tvShowMore.setVisibility(View.GONE);
//setIsRecyclable(true);
Log.d(StringConstants.LOG_TAG, "ShowMore gone");
}
}
Upvotes: 0
Views: 301