我正在尝试创建一个布局管理器,它会水平放置它的孩子,直到它遇到回收器视图的宽度。如果它到达边缘,它应该将孩子排列在下一行。
例如假设回收者视图中有4个项目 - jar
,item1
,item2
和item3
。
item4
和item1
的视图正在彼此相邻排列。还剩下一些空间。但item2
视图无法适应该宽度。所以item3's
转到下一行。但是,留下的差距现在应该在item3
和item1
之间平均分配。
item2
这应该成为
| <item1><item2><--gap-->|
|<-----item3----> |
如果| <--item1--> <--item2-->|
|<-----item3----> |
视图适合item4's
之后的空格,则应将其放置在那里。
item3
这不可能通过| <--item1--> <--item2--> |
|<-----item3----><-item4->|
或GridLayoutManager
实现,因为它们不会考虑单个项目的宽度变化。
要编写自定义布局管理器,我觉得我应该覆盖布局管理器的StaggeredGridLayoutManager
方法。但是我在这一点上有点卡住了。我不知道该如何解决这个问题。任何帮助,将不胜感激。
感谢。
答案 0 :(得分:0)
我有类似的问题,但使用GridLayout解决了这个问题。应该从头开始创建所有视图的缺点:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.GridLayout
android:id="@+id/bubble_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"
android:layout_gravity="top|left"
app:orientation="vertical"
app:columnCount="@integer/grid_cells">
</android.support.v7.widget.GridLayout>
</ScrollView>
这是一个适配器:
public class GridAdapter {
/**
* Indicates maximum filled row in current column, column is the index of arr, row is the value
* [224444555550000000]
* It equals to:
* [***********-------]
* [***********-------]
* [--*********-------]
* [--*********-------]
* [------*****-------]
* [------------------]
*/
private final int[] mRowMatrix;
public GridAdapter(GridLayout gridLayout) {
mGridLayout = gridLayout;
mPlacedList = new ArrayList<>(10);
mUnplacedList = new LinkedList<>();
mNumColumns = ResHelper.getInteger(R.integer.grid_cells);
mMinCells = ResHelper.getInteger(R.integer.min_cells);
mMaxCells = ResHelper.getInteger(R.integer.max_cells);
mRowMatrix = new int[mNumColumns];
}
public void notifyDataSetChanged() {
while (mUnplacedList.size() > 0) {
final int toCol = findColWithMinRow();
final int gapSize = findGapSizeForCol(toCol);
final CustomView view = findAppropriate(gapSize);
if (view == null) {
final int filledRow = toCol > 0
? (toCol + gapSize < mRowMatrix.length ? Math.min(mRowMatrix[toCol - 1], mRowMatrix[toCol + gapSize]) : mRowMatrix[toCol - 1])
: mRowMatrix[gapSize];
for (int j = toCol, jCount = toCol + gapSize; j < jCount; j++) {
mRowMatrix[j] = filledRow;
}
} else {
placeView(view, toCol, mRowMatrix[toCol]);
}
}
}
/**
* Put view in certain column and row in the gridlayout
*/
private void placeView(CustomView view, int toCol, int toRow) {
final int gridSize = view.getGridSize();
final GridLayout.LayoutParams params = new GridLayout.LayoutParams();
params.width = params.height = gridSize * mCellSize;
params.columnSpec = GridLayout.spec(toCol, gridSize);
params.rowSpec = GridLayout.spec(toRow, gridSize);
mPlacedList.add(view);
mUnplacedList.remove(view);
mGridLayout.addView(view, params);
final int filledRow = toRow + gridSize;
for (int j = toCol, count = toCol + gridSize; j < count; j++) {
mRowMap[j] = filledRow;
}
}
/**
* Find empty gap which starts from toCol
* [*********************]
* [******------*****----] here col = 6, size = 3
* [******------*****----]
* [******------*****----]
* [*****************----]
* @param toCol
* @return
*/
private int findGapSizeForCol(int toCol) {
final int fromRow = mRowMatrix[toCol];
int i = toCol;
for (; i < mNumColumns; i++) {
if (fromRow != mRowMatrix[i]) {
break;
}
}
return i - toCol;
}
/**
* Find column with minimum filled row
* [*********************]
* [*****************----] here col = 17
* [******------*****----]
* [******------*****----]
* @return
*/
private int findColWithMinRow() {
int minRow = Integer.MAX_VALUE, minCol = 0;
for (int i = 0, count = mRowMatrix.length; i < count; i++) {
if (minRow > mRowMatrix[i]) {
minRow = mRowMatrix[i];
minCol = i;
}
}
return minCol;
}
/**
* Find customView with appropriate size for the empty gap
*/
private CustomView findAppropriate(int size) {
for (int j = mUnplacedList.size() - 1; j >= 0; j--) {
if (mUnplacedList.get(j).getGridSize() <= size) {
return mUnplacedList.get(j);
}
}
return null;
}
}