如何使用GridLayoutManager与RecyclerView设置列间距? 在我的布局中设置空白/填充没有效果。
当前回答
这是我在Kotlin中编写的更灵活的版本,您可以在dp中设置参数。
class ItemDividerGrid(private val numberOfColumns: Int, private val rowSpacingDP: Float = 0f, private val columnSpacingDP: Float = 0f, private val edgeSpacingVerticalDP: Float = 0f, private val edgeSpacingHorizontalDP: Float = 0f) : ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val numberOfRows = (parent.adapter?.itemCount?:-1)/numberOfColumns
val column = position % numberOfColumns
val row = position / numberOfColumns
val context = view.context
///horizontal
when(column){
0 -> {
outRect.left = convertDpToPixel(edgeSpacingVerticalDP,context)
outRect.right = convertDpToPixel(columnSpacingDP/2, context)
}
numberOfColumns-1 -> {
outRect.left = convertDpToPixel(columnSpacingDP/2, context)
outRect.right = convertDpToPixel(edgeSpacingVerticalDP, context)
}
else -> {
outRect.left = convertDpToPixel(columnSpacingDP/2, context)
outRect.right = convertDpToPixel(columnSpacingDP/2, context)
}
}
//vertical
when(row){
0 -> {
outRect.top = convertDpToPixel(edgeSpacingHorizontalDP,context)
outRect.bottom = convertDpToPixel(rowSpacingDP/2, context)
}
numberOfRows -> {
outRect.top = convertDpToPixel(rowSpacingDP/2, context)
outRect.bottom = convertDpToPixel(edgeSpacingHorizontalDP, context)
}
else -> {
outRect.top = convertDpToPixel(rowSpacingDP/2, context)
outRect.bottom = convertDpToPixel(rowSpacingDP/2, context)
}
}
}
fun convertDpToPixel(dp: Float, context: Context?): Int {
return if (context != null) {
val resources = context.resources
val metrics = resources.displayMetrics
(dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).roundToInt()
} else {
val metrics = Resources.getSystem().displayMetrics
(dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).roundToInt()
}
}
}
其他回答
我根据edwardaa的回答做了一个Kotlin版本
class RecyclerItemDecoration(private val spanCount: Int, private val spacing: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val spacing = Math.round(spacing * parent.context.resources.displayMetrics.density)
val position = parent.getChildAdapterPosition(view)
val column = position % spanCount
outRect.left = spacing - column * spacing / spanCount
outRect.right = (column + 1) * spacing / spanCount
outRect.top = if (position < spanCount) spacing else 0
outRect.bottom = spacing
}
}
如果你已经滚动到这个答案,我写了一个等间距库,支持垂直/水平,LTR/RTL,线性布局/GridLayout管理器和边缘包含。它基本上是一个文件,所以你可以复制粘贴该文件到你的代码中。
我试图支持StaggeredGridLayout,但这个布局返回的跨度索引不可靠。我很乐意听到任何有关这方面的建议。
感谢edwardaa的回答https://stackoverflow.com/a/30701422/2227031
另一点需要注意的是:
如果total spacing和total itemWidth不等于屏幕宽度,您还需要调整itemWidth,例如,在适配器onBindViewHolder方法
Utils.init(_mActivity);
int width = 0;
if (includeEdge) {
width = ScreenUtils.getScreenWidth() - spacing * (spanCount + 1);
} else {
width = ScreenUtils.getScreenWidth() - spacing * (spanCount - 1);
}
int itemWidth = width / spanCount;
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.imageViewAvatar.getLayoutParams();
// suppose the width and height are the same
layoutParams.width = itemWidth;
layoutParams.height = itemWidth;
holder.imageViewAvatar.setLayoutParams(layoutParams);
如果你有一个在列表和网格之间切换的拨动开关,不要忘记在设置任何新的项目装饰之前调用recyclerView.removeItemDecoration(..)。如果不是这样,那么新的间隔计算将是不正确的。
就像这样:
recyclerView.removeItemDecoration(gridItemDecorator)
recyclerView.removeItemDecoration(listItemDecorator)
if (showAsList) {
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recyclerView.addItemDecoration(listItemDecorator)
} else {
recyclerView.layoutManager = GridLayoutManager(this, spanCount)
recyclerView.addItemDecoration(gridItemDecorator)
}
这是我对SpacesItemDecoration的修改,它可以在顶部,底部,左边和右边同样采取numofcolumns和空间。
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
private int mNumCol;
public SpacesItemDecoration(int space, int numCol) {
this.space = space;
this.mNumCol=numCol;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
//outRect.right = space;
outRect.bottom = space;
//outRect.left = space;
//Log.d("ttt", "item position" + parent.getChildLayoutPosition(view));
int position=parent.getChildLayoutPosition(view);
if(mNumCol<=2) {
if (position == 0) {
outRect.left = space;
outRect.right = space / 2;
} else {
if ((position % mNumCol) != 0) {
outRect.left = space / 2;
outRect.right = space;
} else {
outRect.left = space;
outRect.right = space / 2;
}
}
}else{
if (position == 0) {
outRect.left = space;
outRect.right = space / 2;
} else {
if ((position % mNumCol) == 0) {
outRect.left = space;
outRect.right = space/2;
} else if((position % mNumCol) == (mNumCol-1)){
outRect.left = space/2;
outRect.right = space;
}else{
outRect.left=space/2;
outRect.right=space/2;
}
}
}
if(position<mNumCol){
outRect.top=space;
}else{
outRect.top=0;
}
// Add top margin only for the first item to avoid double space between items
/*
if (parent.getChildLayoutPosition(view) == 0 ) {
} else {
outRect.top = 0;
}*/
}
}
并在逻辑上使用下面的代码。
recyclerView.addItemDecoration(new SpacesItemDecoration(spacingInPixels, numCol));
推荐文章
- 改变开关的“开”色
- 以编程方式将EditText的输入类型从PASSWORD更改为NORMAL,反之亦然
- 如何在隐藏和查看密码之间切换
- 在Android上调整一个大的位图文件到缩放输出文件
- 如何更改Android版本和代码版本号?
- Android Studio突然无法解析符号
- 应用程序重新启动而不是恢复
- 如何设置整个应用程序在纵向模式?
- Android中文本的阴影效果?
- 以编程方式设置TextView的布局权重
- Android -如何覆盖“后退”按钮,所以它不完成()我的活动?
- 如何从通知点击发送参数到一个活动?
- 导航目标xxx对于这个NavController是未知的
- 使用ConstraintLayout均匀间距的视图
- 文件google-services错误。模块根文件夹中缺少Json。谷歌服务插件没有它就不能正常工作。