1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
| package com.tyl.baseMoudle.utils;
import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.util.SparseArray; import android.view.View;
import com.tyl.baseMoudle.interfaces.PageDecorationLastJudge;
public class HorizontalPageLayoutManager extends RecyclerView.LayoutManager implements PageDecorationLastJudge {
@Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return null; }
int totalHeight = 0; int totalWidth = 0; int offsetY = 0; int offsetX = 0;
public HorizontalPageLayoutManager(int rows, int columns) { this.rows = rows; this.columns = columns; this.onePageSize = rows * columns; }
@Override public boolean canScrollHorizontally() { return true; }
@Override public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { detachAndScrapAttachedViews(recycler); int newX = offsetX + dx; int result = dx; if (newX > totalWidth) { result = totalWidth - offsetX; } else if (newX < 0) { result = 0 - offsetX; } offsetX += result; offsetChildrenHorizontal(-result); recycleAndFillItems(recycler, state); return result; }
private SparseArray<Rect> allItemFrames = new SparseArray<>();
private int getUsableWidth() { return getWidth() - getPaddingLeft() - getPaddingRight(); }
private int getUsableHeight() { return getHeight() - getPaddingTop() - getPaddingBottom(); }
int rows = 0; int columns = 0; int pageSize = 0; int itemWidth = 0; int itemHeight = 0; int onePageSize = 0; int itemWidthUsed; int itemHeightUsed;
@Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() == 0) { removeAndRecycleAllViews(recycler); return; } if (state.isPreLayout()) { return; } //获取每个Item的平均宽高 itemWidth = getUsableWidth() / columns; itemHeight = getUsableHeight() / rows;
//计算宽高已经使用的量,主要用于后期测量 itemWidthUsed = (columns - 1) * itemWidth; itemHeightUsed = (rows - 1) * itemHeight;
//计算总的页数
// pageSize = state.getItemCount() / onePageSize + (state.getItemCount() % onePageSize == 0 ? 0 : 1); computePageSize(state); Log.i("zzz", "itemCount=" + getItemCount() + " state itemCount=" + state.getItemCount() + " pageSize=" + pageSize); //计算可以横向滚动的最大值 totalWidth = (pageSize - 1) * getWidth();
//分离view detachAndScrapAttachedViews(recycler);
int count = getItemCount(); for (int p = 0; p < pageSize; p++) { for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { int index = p * onePageSize + r * columns + c; if (index == count) { //跳出多重循环 c = columns; r = rows; p = pageSize; break; }
View view = recycler.getViewForPosition(index); addView(view); //测量item measureChildWithMargins(view, itemWidthUsed, itemHeightUsed);
int width = getDecoratedMeasuredWidth(view); int height = getDecoratedMeasuredHeight(view); //记录显示范围 Rect rect = allItemFrames.get(index); if (rect == null) { rect = new Rect(); } int x = p * getUsableWidth() + c * itemWidth; int y = r * itemHeight; rect.set(x, y, width + x, height + y); allItemFrames.put(index, rect);
} } //每一页循环以后就回收一页的View用于下一页的使用 removeAndRecycleAllViews(recycler); }
recycleAndFillItems(recycler, state); }
private void computePageSize(RecyclerView.State state) { pageSize = state.getItemCount() / onePageSize + (state.getItemCount() % onePageSize == 0 ? 0 : 1); }
@Override public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { super.onDetachedFromWindow(view, recycler); offsetX = 0; offsetY = 0; }
private void recycleAndFillItems(RecyclerView.Recycler recycler, RecyclerView.State state) { if (state.isPreLayout()) { return; }
Rect displayRect = new Rect(getPaddingLeft() + offsetX, getPaddingTop(), getWidth() - getPaddingLeft() - getPaddingRight() + offsetX, getHeight() - getPaddingTop() - getPaddingBottom()); Rect childRect = new Rect(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); childRect.left = getDecoratedLeft(child); childRect.top = getDecoratedTop(child); childRect.right = getDecoratedRight(child); childRect.bottom = getDecoratedBottom(child); if (!Rect.intersects(displayRect, childRect)) { removeAndRecycleView(child, recycler); } }
for (int i = 0; i < getItemCount(); i++) { if (Rect.intersects(displayRect, allItemFrames.get(i))) { View view = recycler.getViewForPosition(i); addView(view); measureChildWithMargins(view, itemWidthUsed, itemHeightUsed); Rect rect = allItemFrames.get(i); layoutDecorated(view, rect.left - offsetX, rect.top, rect.right - offsetX, rect.bottom); } }
}
@Override public boolean isLastRow(int index) { if (index >= 0 && index < getItemCount()) { int indexOfPage = index % onePageSize; indexOfPage++; if (indexOfPage > (rows - 1) * columns && indexOfPage <= onePageSize) { return true; } }
return false; }
@Override public boolean isLastColumn(int position) { if (position >= 0 && position < getItemCount()) { position++; if (position % columns == 0) { return true; } } return false; }
@Override public boolean isPageLast(int position) { position++; return position % onePageSize == 0; }
@Override public int computeHorizontalScrollRange(RecyclerView.State state) { computePageSize(state); return pageSize * getWidth(); }
@Override public int computeHorizontalScrollOffset(RecyclerView.State state) { return offsetX; }
@Override public int computeHorizontalScrollExtent(RecyclerView.State state) { return getWidth(); } }
|