如何在方向更改后阻止StaggeredGridLayoutManager中的项目重新排序?

时间:2015-08-04 10:06:15

标签: android image android-recyclerview picasso staggeredgridlayout

我知道这个问题听起来与StackOverflow上的其他问题类似,但这是关于在方向改变后发生的事情。

我有一个带有工具栏和RecyclerView的Activity。我使用具有垂直方向和3列的StaggeredGridLayoutManager来填充RecyclerView。项目布局是一个包含ImageView和TextView的LinearLayout。

<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>

图像从网络加载。我知道ViewHolders绑定之前的图像大小。所以我在onBindViewHolder中设置图像高度以防止项目重新排序并通过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
}

假设我的适配器中有50个项目。我处于纵向模式并向下滚动20个项目。然后我改为横向模式。我创建了一个新的StaggeredGridLayoutManager,现在有4列,所以比纵向模式多一个。我重新计算图像高度以适应新的目标宽度,并在布局上设置保存状态,如下所示:

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);

网格自动滚动到所需的存储位置。现在我向上滚动。由于新的图像尺寸,“滚动位置上方的空间”不能完全由图像填充。因此,项目会重新排序,但大多数时候网格顶部仍然存在或多或少的差距(请参见底部的屏幕截图链接)。当我甩到顶端时,这是最糟糕的。那么有没有办法防止重新排序和这种情况下的差距?

portrait mode显示第一次刚加载时的屏幕。

landscape mode在方向更改后向上滚动时显示屏幕。左边的图像几乎是透明的,因为我猜想自定义淡入淡出动画。我从示例代码中删除了它以使其更小。

编辑:

我刚刚意识到方向改变后所有项目都在屏幕顶部对齐。虽然看起来不错,但我更倾向于回收者视图顶部的对齐是否合适。

1 个答案:

答案 0 :(得分:2)

所以我想出了一个解决方法。简而言之,当网格一直滚动到顶部时,我将差距策略设置为GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS,以便重新排列项目。

以下是更详细的说明。当使用保存的实例状态调用onActivityCreated时,我会检查方向是否已更改。如果有,我设置一个标志。在onScrollStateChanged回调中,我检查第一个可见项位置之一是否为0.这就是我认为“滚动到顶部”。因此,如果用户滚动到顶部并更改了方向,我会调用layoutMgr.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);layoutMgr.invalidateSpanAssignments();(并重置标记)。