The problem here is that you create different list items for the recycler view, which is ok at first but when you scroll, the recyclerView trys to recycle an old view with n amount of subHeaders and insert new data that may contain m!=n amount of subHeaders. there are several solutions, if you know of a constant and low number of different views (lets say you know you can have between 3 and 5 subHeaders ---> 3 different view typs) you can create a recycler view with different view types ceckout this stackOverflow answer. another solution is to create a costum view group and measure it acourding to the number of subHeaders (if you do this you do not need a list item xml file).
public class ItemView extends ViewGroup {
private static Paint mPaint;
private final ImageView mAvatar;
protected final TextView mText;
private final TextView mAuthor;
public ItemView(Context context) {
super(context);
setWillNotDraw(false);
mAvatar = new ImageView(context);
int size = getResources().getDimensionPixelSize(R.dimen.avatar_size);
mAvatar.setLayoutParams(new LayoutParams(size, size));
addView(mAvatar);
Point p = new Point();
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
display.getSize(p);
mText = new TextView(context);
addView(mText);
mAuthor = new TextView(context);
mAuthor.setSingleLine();
addView(mAuthor);
}
public void setData(Status item) {
AppContext.getImageHandler().load(item.getUser().getProfileImageURL(), mAvatar);
mAuthor.setText(item.getUser().getName());
mText.setText(item.getText());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = measureAllChildren(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), height);
}
protected int measureAllChildren(int widthMeasureSpec, int heightMeasureSpec) {
int m = getResources().getDimensionPixelSize(R.dimen.margin);
measureChild(mAvatar, widthMeasureSpec, heightMeasureSpec);
measureChild(mAuthor, widthMeasureSpec, heightMeasureSpec);
measureChild(mText, MeasureSpec.makeMeasureSpec(getMeasuredWidth() - 2 * m, MeasureSpec.EXACTLY), heightMeasureSpec);
mAvatar.layout(m, m, m + mAvatar.getMeasuredWidth(), m + mAvatar.getMeasuredHeight());
mAuthor.layout(mAvatar.getRight() + m, mAvatar.getTop(), mAvatar.getRight() + m + mAuthor.getMeasuredWidth(), m + mAuthor.getMeasuredHeight());
mText.layout(m, m + mAvatar.getBottom(), getMeasuredWidth(), m + mAvatar.getBottom() + mText.getMeasuredHeight());
return calculateFinalHeight(m);
}
protected int calculateFinalHeight(int margin) {
return mText.getBottom() + margin;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPaint == null) {
mPaint = new Paint();
mPaint.setColor(Color.rgb(160, 200, 220));
mPaint.setStrokeWidth(getResources().getDisplayMetrics().density);
}
canvas.drawLine(0, getHeight(), getWidth(), getHeight(), mPaint);
}
}
you can use the measureAllChildren method to measure all of the subHeaders and then use calculateFinalHeight() to measur the final hight accourding to the last subheader.
if you use a costum view group than your methods inside the adapter can look like this:
// Create new views (invoked by the layout manager)
@Override
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
ItemView itemView = new ItemView(context);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
((ItemView) holder.itemView).setData(mItems.get(position));
}
final class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final Context context;
public ViewHolder(ItemView v) {
super(v);
context = v.getContext();
v.setOnClickListener(this);
}
@Override
public void onClick(View v) {
dispatchIntent();
}
}
good luck :)