My issue is when Recycler View is scrolling Up and Down
Here how i am setting My Recycler view in Fragment.
private void setRecyclerView() {
recyclerView.setHasFixedSize(true);
StaggeredGridLayoutManager layoutManager =
new StaggeredGridLayoutManager(2, 1);
recyclerView.setLayoutManager(layoutManager);
adapter = new TwitterTweetAdapter(getActivity());
// setting every thing false in item animator
recyclerView.setItemAnimator(new RecyclerView.ItemAnimator() {
@Override
public void runPendingAnimations() {
}
@Override
public boolean animateRemove(RecyclerView.ViewHolder viewHolder) {
return false;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder viewHolder) {
return false;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder viewHolder, int i, int i2, int i3, int i4) {
return false;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder viewHolder2, int i, int i2, int i3, int i4) {
return false;
}
@Override
public void endAnimation(RecyclerView.ViewHolder viewHolder) {
}
@Override
public void endAnimations() {
}
@Override
public boolean isRunning() {
return false;
}
});
recyclerView.setAdapter(adapter);
}
Here is My Adapter Class
In My Adapter I am setting One Header
//My ViewHolders
class Header extends RecyclerView.ViewHolder {
@Bind(R.id.feed_head)
CardView feedHeader;
@Bind(R.id.feed_header_count)
TextView userCount;
@Bind(R.id.feed_header_text)
TextView userText;
public TwitterHeader(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public static class RowViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.feed_row_view)
CardView feedRow;
@Bind(R.id.feed_image)
ImageView feedImage;
@Bind(R.id.video_play_icon)
ImageButton playButton;
@Bind(R.id.feed_description)
TextView feedDescription;
@Bind(R.id.feed_user_image)
ImageView userImage;
@Bind(R.id.feed_user_name)
TextView userName;
@Bind(R.id.feed_time)
TextView feedDate;
@Bind(R.id.feed_progress_bar)
ProgressBar progressBar;
public RowViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
// declaration of variables
private static final int TYPE_HEADER = 0;
private static final int TYPE_FEED = 1;
Context context;
private Activity activity;
private List<MockData> dataLists;
public static List<MockData> dataListsupdated;
int userSearchCount;
// constructor
public FeedAdapter(Activity activity) {
this.activity = activity;
}
// setting data list
public void setDataList(List<MockData> dataLists, int userSearchCount, float density) {
this.dataLists = dataLists;
this.density = density;
this.userSearchCount = userSearchCount;
}
// onCreateViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == TYPE_HEADER) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.feed_header, viewGroup, false);
return new Header(view);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.feed_row, viewGroup, false);
return new RowViewHolder(v);
}
}
// onBindViewHolder i am bind my view with data.
if (holder instanceof Header) {
Header header = (Header) holder;
if (userSearchCount == 20) {
header.userCount.setText(R.string.twitter_default_count);
} else {
header.userCount.setText(userSearchCount);
}
header.userText.setText(R.string.user);
header.feedHeader.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(activity, TwitterSearchActivity.class);
activity.startActivity(intent);
}
});
} else {
if (holder instanceof RowViewHolder) {
final RowViewHolder rowViewHolder = (RowViewHolder) holder;
final MockData responseList = dataLists.get(position);
rowWidth = rowViewHolder.feedImage.getWidth();
rowViewHolder.playButton.setVisibility(View.GONE);
if (responseList.text.startsWith("RT")) {
rowViewHolder.feedRow.setVisibility(View.GONE);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);
rowViewHolder.feed.setLayoutParams(params);
} else {
setRowImage(rowViewHolder, responseList);
rowViewHolder.feedDescription.setText(responseList.text);
rowViewHolder.userImage.setVisibility(View.VISIBLE);
Glide.with(activity)
.load(responseList.user.profileImageUrlHttps)
.into(rowViewHolder.userImage);
rowViewHolder.userName.setText(responseList.user.screenName);
Date date = new Date(responseList.createdAt);
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(activity.getApplicationContext());
rowViewHolder.feedDate.setText(dateFormat.format(date));
rowViewHolder.feedRow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(position);
}
});
}
}
}
}
// setting Row Image.
private void setRowImage(RowViewHolder rowViewHolder, Tweet responseList) {
if (responseList.entities.media != null) {
MediaEntity mediaEntity = responseList.entities.media.get(0);
if (mediaEntity.mediaUrlHttps != null) {
int height = mediaEntity.sizes.medium.h;
int width = mediaEntity.sizes.medium.w;
int ratio = width / 143;
int newHeight = (int) ((height / ratio) * density);
Glide.with(activity)
.load(mediaEntity.mediaUrlHttps)
.override(width, newHeight)
.placeholder(R.color.colorAccent)
.into(rowViewHolder.feedImage);
} else {
rowViewHolder.feedImage.setImageDrawable(null);
}
} else {
rowViewHolder.feedImage.setImageDrawable(null);
}
}
// View condition to set header and row.
@Override
public int getItemViewType(int position) {
if (isPositionHeader(position))
return TYPE_HEADER;
return TYPE_FEED;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
@Override
public int getItemCount() {
return dataLists == null ? 0 : dataLists.size();
}
}
I have a very similar Adapter in my app where I display feed from Facebook instead of Twitter, First of all, switch to Glide instead of Picasso since it has gives better caching and image loading with RecyclerView, check THIS. So coming to your problem now, call setHasStableIds(true) on your Adapter in the 1st step, override the getItemId method to return a suitable long from your Adapter, since you are using a feed, you can compute a hash say for the postId or some field that unique identifies each post within a feed. My feed has an optional image too which is why I have these 2 methods
public void setProfilePicture(String uri) {
//As per the solution discussed here http://stackoverflow.com/questions/32706246/recyclerview-adapter-and-glide-same-image-every-4-5-rows
if (uri != null) {
Glide.with(mContext)
.load(uri)
.asBitmap()
.transform(new CropCircleTransform(mContext))
.into(mProfilePicture);
} else {
Glide.clear(mProfilePicture);
mProfilePicture.setImageResource(R.drawable.com_facebook_profile_picture_blank_square);
}
}
public void setPostPicture(String uri) {
//As per the solution discussed here http://stackoverflow.com/questions/32706246/recyclerview-adapter-and-glide-same-image-every-4-5-rows
if (uri != null) {
Glide.with(mContext)
.load(uri)
.asBitmap()
.transform(new CropTransformation(mContext, mPostImageWidth, mPostImageHeight))
.into(mPostPicture);
} else {
Glide.clear(mPostPicture);
mPostPicture.setImageDrawable(null);
}
}
and then all you gotta do is call these methods from your onBindViewHolder to set the Image. Post is my object that contains the details of a single post such as name, userid , image url for the person s picture and image url for the post picture which is optional. Let me know if you encounter any issues further.
@Override
public void onBindViewHolder(ItemHolder holder, int position) {
Post post = mResults.get(position);
holder.setUserName(post.getUserName());
holder.setUpdatedTime(post.getUpdatedTime());
holder.setMessage(post.getMessage(), mState, position);
holder.setPostPicture(post.getPicture());
holder.setProfilePicture(post.getUserPicture());
// Check for an expanded view, collapse if you find one
}