How to prevent reordering of elements in StaggeredGridLayoutManager after changing orientation?

I know this question sounds similar to the others in StackOverflow, but this is about what happens after the orientation changes.

I have an Activity with a toolbar and a RecyclerView. I use a StaggeredGridLayoutManager with a vertical orientation and 3 columns to populate a RecyclerView. The element layout is a LinearLayout containing an ImageView and a TextView.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/grid_item_margin" android:orientation="vertical"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="centerCrop" /> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="2dp" android:paddingTop="2dp" /> </LinearLayout> 

Images are downloaded from the Internet. I know the size of the image before snapping ViewHolders. Therefore, I set the height of the image in onBindViewHolder to prevent reordering the elements and loading the image through Picasso:

 @Override public void onBindViewHolder(ViewHolder holder, int position) { ViewGroup.LayoutParams lp = holder.imageView.getLayoutParams(); lp.height = imageInfos.get(position).imageHeight; holder.imageView.setLayoutParams(lp); mPicasso.load(url) .noFade() .into(holder.imageView); // imageView scaleType=centerCrop } 

Say I have 50 elements in my adapter. I am in portrait mode and scroll through 20 items. Then I go into landscape mode. Now I am creating a new StaggeredGridLayoutManager with 4 columns, so one more than in portrait mode. I recalculate the height of the image according to the new target width and set the saved state on the layout as follows:

 ArrayList<ImageInfo> imageInfos = savedInstanceState .getParcelableArrayList(IMG_INFOS_KEY); setNewImgTargetDimensions(imageInfos, columns); mAdapter = new ImageGridAdapter(mPicasso, imageInfos); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setLayoutManager(layoutMgr); Parcelable sglmState = savedInstanceState .getParcelable(LAYOUT_MGR_STATE_KEY); mRecyclerView.getLayoutManager() .onRestoreInstanceState(sglmState); 

The grid automatically scrolls to the desired saved position. Now I scroll up. Due to the new size of the image, the โ€œspace over the scroll positionโ€ cannot be completely filled with images. Thus, the elements are reordered, but most of the time in the upper part of the grid there is still a more or less large gap (see links to screenshots below). This is the worst when I rush to the top. So, is there a way to prevent reordering and spaces in this case?

Portrait mode shows the screen on first boot.

landscape mode shows the screen when scrolling after changing orientation. The image on the left is almost transparent due to custom fading in the animation, I think. I removed this from the sample code to reduce it.

Edit:

I just realized that all the elements are aligned at the top of the screen after changing the orientation. Although this looks beautiful, I would prefer the alignment at the very top of the recycler window to be correct.

+4
source share
1 answer

So, I came up with a workaround. In short, when the grid scrolls to the very top, I set the break strategy GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS so that the elements are regrouped.

Here is a more detailed description. When onActivityCreated is called with the instance state stored, I check to see if the orientation has changed. If it is, I set the flag. In the onScrollStateChanged I check to see if one of the first visible positions of positions is 0. This is what I consider to be "scrolled up." Therefore, if the user scrolls up and the orientation changes, I call layoutMgr.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); and layoutMgr.invalidateSpanAssignments(); (and reset the flag).

+2
source

All Articles