import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.android.code.databinding.ActivityHome2Binding
import com.android.code.ui.FlowLayoutManager
class HomeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHome2Binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHome2Binding.inflate(layoutInflater)
setContentView(binding.root)
initView()
}
private fun initView() {
binding.recyclerView.layoutManager = FlowLayoutManager()
binding.recyclerView.adapter = SimpleAdapter()
}
}
import android.view.Gravity
import android.view.ViewGroup
import android.widget.Button
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
class SimpleAdapter : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val button = Button(parent.context)
button.text = "hello"
button.gravity = Gravity.CENTER
button.isAllCaps = false
return object : ViewHolder(button) {}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {}
override fun getItemCount() = 1000
}
import android.graphics.Rect;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
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;
recycleOrFillItemView(recycler, state);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int offsetY = dy;
if (verticalScrollOffset + dy < 0) {
offsetY = -verticalScrollOffset;
} else if (verticalScrollOffset + dy > totalHeight - getHeight()) {
offsetY = totalHeight - getHeight() - verticalScrollOffset;
}
verticalScrollOffset += offsetY;
offsetChildrenVertical(offsetY);
recycleOrFillItemView(recycler, state);
return offsetY;
}
@Override
public boolean canScrollVertically() {
return true;
}
protected void recycleOrFillItemView(RecyclerView.Recycler recycler, RecyclerView.State state) {
Rect phoneFrame = new Rect(0, verticalScrollOffset, getWidth(), verticalScrollOffset + getHeight());
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);
}
}
}