前言
RecyclerView的核心功能,并不是由自己来完成的,而是转交给LayoutManager来完成的
LayoutManager负责的功能有:布局管理,滑动管理,缓存管理
自定义流式布局管理器 - FlowLayoutManager
这里,我们自定义了一个流式布局管理器,来演示LayoutManager是如何工作的
代码比较简单,对标准流程做了简化了,主要是为了演示,在性能和和细节上并不够好
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
FlowLayoutManager layoutManager = new FlowLayoutManager();
recyclerView.setLayoutManager(layoutManager);
Adapter adapter = new Adapter();
recyclerView.setAdapter(adapter);
}
}
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
String[] datas = new String[300];
public Adapter() {
initData();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view_pager, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.btn.setText(datas[position]);
}
@Override
public int getItemCount() {
return datas.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
Button btn;
public ViewHolder(View itemView) {
super(itemView);
btn = itemView.findViewById(R.id.btn);
}
}
protected void initData() {
String[] randoms = new String[]{"X", "XXXXXX", "XXXXXXXXXXXXX", "XXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX", "XXX", "XXXXXXXXXXXXX"};
for (int i = 0; i < datas.length; i++)
datas[i] = randoms[(int) (Math.random() * randoms.length)];
}
}
public class FlowLayoutManager extends RecyclerView.LayoutManager {
int totalHeight = 0;
SparseArray<Rect> itemBounds = new SparseArray<>();
int verticalScrollOffset = 0;
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0)
return;
if (state.isPreLayout())
return;
detachAndScrapAttachedViews(recycler);
int offsetY = 0;
int offsetX = 0;
int itemHeight = 0;
for (int i = 0; i < getItemCount(); i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int w = getDecoratedMeasuredWidth(view);
int h = getDecoratedMeasuredHeight(view);
itemHeight = h;
Rect bound = itemBounds.get(i);
if (bound == null)
bound = new Rect();
if (offsetX + w > getWidth()) {
offsetY += h;
offsetX = w;
bound.set(0, offsetY, w, offsetY + h);
} else {
bound.set(offsetX, offsetY, offsetX + w, offsetY + h);
offsetX += w;
}
itemBounds.put(i, bound);
}
totalHeight = offsetY + itemHeight;
recyclerViewFillView(recycler, state);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int trval = dy;
if (verticalScrollOffset + dy < 0) {
trval = -verticalScrollOffset;
} else if (verticalScrollOffset + dy > totalHeight - getHeight()) {
trval = totalHeight - getHeight() - verticalScrollOffset;
}
verticalScrollOffset += trval;
offsetChildrenVertical(trval);
recyclerViewFillView(recycler, state);
return trval;
}
@Override
public boolean canScrollVertically() {
return true;
}
protected void recyclerViewFillView(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
Rect phoneFrame = new Rect(0, verticalScrollOffset, getWidth(), verticalScrollOffset + getHeight());
Rect childRect = new Rect();
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
Rect child = itemBounds.get(i);
if (!Rect.intersects(phoneFrame, child))
removeAndRecycleView(childView, recycler);
}
for (int j = 0; j < getItemCount(); j++)
if (Rect.intersects(phoneFrame, itemBounds.get(j))) {
View scrap = recycler.getViewForPosition(j);
measureChildWithMargins(scrap, 0, 0);
addView(scrap);
Rect frame = itemBounds.get(j);
layoutDecorated(scrap, frame.left, frame.top - verticalScrollOffset, frame.right, frame.bottom - verticalScrollOffset);
}
}
}
源码下载
Android自定义FlowLayoutManager
|