如何确定交错网格布局管理器中的列位置
How to determine column position in staggered grid layout manager
我正在为照片列表使用交错的回收视图布局。我希望两侧的间距为零,同时两列之间仍然有 space。我正在使用项目装饰子 class 来获得所附照片中看到的间距。我知道我可以控制左右间距,但问题是我永远不知道照片在哪一列。交错布局管理器似乎会自行重新排序。我试过使用 getChildAdapterPosition
但它似乎 return 数据源数组中的位置而不是照片在布局中的实际位置。知道我应该如何处理这个吗?
所以我能够使用的一个解决方案是使用项目装饰器,但这确实有点 weird/hacky 的感觉。
基本上,您将根据项目的列位置(或类似位置)调整项目的外部矩形。我的理解是外部矩形或多或少是您想要更改的间距。试试下面的代码,显然您需要对 'calculate' 项目所在的列进行自己的调整和逻辑,但这应该足以弄清楚,希望:
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int left = outRect.left;
int right = outRect.right;
int top = outRect.top;
int bottom = outRect.bottom;
int idx = parent.getChildPosition(view);
int perRow = gridLayoutManager.getSpanCount();
int adj = blahh... // some adjustment
if (idx < itemsPerRow) {
// on first row, adjust top if needed
}
if(idx % perRow == 0){
// on first column, adjust. Left magically adjusts bottom, so adjust it too...
left += adj;
bottom -= adj;
}
if(idx % itemsPerRow == perRow - 1){
// on last column, adjust. Right magically adjusts bottom, so adjust it too...
right += adjustment;
bottom -= adjustment;
}
outRect.set(left, top, right, bottom);
}
});
同样,这很棘手,需要反复试验才能正确。
我尝试过的另一种成功的解决方案是为不同的列定义不同的视图。在您的情况下,列将在左侧和右侧具有不同的负边距视图以获得您想要的效果。
附带说明一下,我假设您在卡片视图上使用了海拔高度。我注意到的一件事是,如果卡片视图没有高度,而是你自己处理它(是的,我知道,不自己处理高度不是重点)大部分困难都会消失,事情开始表现,可能是因为 elevation/shadow 计算。但无论如何...希望这至少能有所帮助...
我设法让它工作了。在我的例子中,我不需要在屏幕的左边缘或右边缘有任何边框。我只需要中间和底部的边框。解决方案是获取 StaggeredGridLayoutManager.LayoutParams 类型的视图的布局参数。在这些参数中,您可以获得 spanIndex,它告诉您视图位于哪个索引上。因此,如果您的 spanCount 为 2,则左视图的 spanIndex 将为 0,而右视图的 spanIndex 将为 1。
这是我的代码,也许对你有帮助。
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
int spanIndex = lp.getSpanIndex();
if (position > 0) {
if (spanIndex == 1) {
outRect.left = space;
} else {
outRect.right = space;
}
outRect.bottom = space * 2;
}
}
}
在我的例子中,首先我必须获得位置,因为在索引 0 上我有一个 header 视图,它没有任何边框。之后,我得到了跨度索引,并根据它在该视图上设置了我需要的边框。最后我在每个视图上设置了底部边框。
我正在为照片列表使用交错的回收视图布局。我希望两侧的间距为零,同时两列之间仍然有 space。我正在使用项目装饰子 class 来获得所附照片中看到的间距。我知道我可以控制左右间距,但问题是我永远不知道照片在哪一列。交错布局管理器似乎会自行重新排序。我试过使用 getChildAdapterPosition
但它似乎 return 数据源数组中的位置而不是照片在布局中的实际位置。知道我应该如何处理这个吗?
所以我能够使用的一个解决方案是使用项目装饰器,但这确实有点 weird/hacky 的感觉。
基本上,您将根据项目的列位置(或类似位置)调整项目的外部矩形。我的理解是外部矩形或多或少是您想要更改的间距。试试下面的代码,显然您需要对 'calculate' 项目所在的列进行自己的调整和逻辑,但这应该足以弄清楚,希望:
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int left = outRect.left;
int right = outRect.right;
int top = outRect.top;
int bottom = outRect.bottom;
int idx = parent.getChildPosition(view);
int perRow = gridLayoutManager.getSpanCount();
int adj = blahh... // some adjustment
if (idx < itemsPerRow) {
// on first row, adjust top if needed
}
if(idx % perRow == 0){
// on first column, adjust. Left magically adjusts bottom, so adjust it too...
left += adj;
bottom -= adj;
}
if(idx % itemsPerRow == perRow - 1){
// on last column, adjust. Right magically adjusts bottom, so adjust it too...
right += adjustment;
bottom -= adjustment;
}
outRect.set(left, top, right, bottom);
}
});
同样,这很棘手,需要反复试验才能正确。
我尝试过的另一种成功的解决方案是为不同的列定义不同的视图。在您的情况下,列将在左侧和右侧具有不同的负边距视图以获得您想要的效果。
附带说明一下,我假设您在卡片视图上使用了海拔高度。我注意到的一件事是,如果卡片视图没有高度,而是你自己处理它(是的,我知道,不自己处理高度不是重点)大部分困难都会消失,事情开始表现,可能是因为 elevation/shadow 计算。但无论如何...希望这至少能有所帮助...
我设法让它工作了。在我的例子中,我不需要在屏幕的左边缘或右边缘有任何边框。我只需要中间和底部的边框。解决方案是获取 StaggeredGridLayoutManager.LayoutParams 类型的视图的布局参数。在这些参数中,您可以获得 spanIndex,它告诉您视图位于哪个索引上。因此,如果您的 spanCount 为 2,则左视图的 spanIndex 将为 0,而右视图的 spanIndex 将为 1。
这是我的代码,也许对你有帮助。
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
int spanIndex = lp.getSpanIndex();
if (position > 0) {
if (spanIndex == 1) {
outRect.left = space;
} else {
outRect.right = space;
}
outRect.bottom = space * 2;
}
}
}
在我的例子中,首先我必须获得位置,因为在索引 0 上我有一个 header 视图,它没有任何边框。之后,我得到了跨度索引,并根据它在该视图上设置了我需要的边框。最后我在每个视图上设置了底部边框。