I have created a very simple project, displaying 28 images with StaggeredGridLayoutManager
by recyclerview. but as I scroll the recyclerview it moves items for example from left to right or swap the column of left and right.
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
public class MainActivity extends Activity {
String mImageDir;
private RecyclerView mRecyclerView;
private StaggeredGridLayoutManager mLayoutManager;
MyRecyclerAdapter myRecyclerAdapter;
List<ImageModel> mImageList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview_rootview);
mLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(false);
mImageList = new ArrayList<ImageModel>();
for (int i = 1; i < 29 ; i++) {
ImageModel img = new ImageModel();
img.setTitle("Image No " + i);
int drawableResourceId = this.getResources().getIdentifier("image"+String.valueOf(i), "drawable", this.getPackageName());
img.setResId(drawableResourceId);
mImageList.add(img);
}
myRecyclerAdapter = new MyRecyclerAdapter(MainActivity.this,mImageList);
mRecyclerView.setAdapter(myRecyclerAdapter);
}
}
And the adapter:
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
private List<ImageModel> mItems;
Context mContext;
public MyRecyclerAdapter(Context context,List<ImageModel> objects) {
mContext = context;
mItems = objects;
}
static class ViewHolder extends RecyclerView.ViewHolder{
public ImageView mImageView;
public TextView mTextView;
public View rootView;
public ViewHolder(View itemView) {
super(itemView);
rootView = itemView;
mImageView =(ImageView)itemView.findViewById(R.id.image);
mTextView =(TextView)itemView.findViewById(R.id.title);
}
}
@Override
public int getItemCount() {
return mItems.size();
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ImageModel item = mItems.get(position);
Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
holder.mTextView.setText(item.getTitle());
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
LayoutInflater inflater =
(LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View convertView = inflater.inflate(R.layout.item, parent, false);
return new ViewHolder(convertView);
}
}
http://i.imgur.com/FUapm2K.gif?1
if you play (scroll up and down) you can discover more interesting animation :-)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ImageModel item = mItems.get(position);
RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams)holder.mImageView.getLayoutParams();
float ratio = item.getHeight()/item.getWidth();
rlp.height = (int)(rlp.width * ratio);
holder.mImageView.setLayoutParams(rlp);
Picasso.with(mContext).load(item.getResId()).into(holder.mImageView);
holder.mTextView.setText(item.getTitle());
}
What worked for me was to disable all animation on the recycle view when using StaggeredGridLayoutManager.
mRecyclerView.setItemAnimator(null);
You can create your own animator if you only want to restrict moving animations and keep the add and remove item animations.
This is happening because SGLM does not keep any w/h information about the views. So each time a View is rebound, it gets the place holder size first and then the final size when the image is loaded.
Loading the actual image w/ different size (than place holder) triggers a new layout request, and during that layout request, SGLM detects that there will be gaps in the UI (or some item w/ higher position appears below an item w/ lower position) thus re-orders items w/ an animation.
You can avoid it by setting your place holder image to the dimensions of the actual image. If you don't have it ahead of time, you can save them after the image is loaded for the first-time and use it in the next onBind call.
You can try this
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setLayoutManager(manager);
after you set this, you'll find there is a blank at the top when you scroll to the top. continue to set this
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
((StaggeredGridLayoutManager)recyclerView.getLayoutManager()).invalidateSpanAssignments();
}
});
It's work for me, I get this way somewhere. I hope it can help you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With