我尝试在不使用外部库的情况下制作粘性 recyclerView,直到现在我能够使用 Header 显示 Recyclerview 中的项目列表。但是当我滚动 recyclerview 时,初始 HeaderData 不会被即将到来的 Header 数据推送。
主要活动
public class MainActivity extends AppCompatActivity {
ActivityMainBinding mBinding;
StickyAdapter mStickyAdapter;
List<MenuItem> listMenuItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
listMenuItem = new ArrayList<>();
listMenuItem.add(new MenuItem("Header", MenuItem.HEADER_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Header1", MenuItem.HEADER_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Header2", MenuItem.HEADER_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Header3", MenuItem.HEADER_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Header4", MenuItem.HEADER_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE));
mStickyAdapter = new StickyAdapter(listMenuItem);
mBinding.rvSticky.setLayoutManager(new LinearLayoutManager(this));
mBinding.rvSticky.setHasFixedSize(true);
mBinding.rvSticky.addItemDecoration(new ItemDecoration(mBinding.rvSticky, mStickyAdapter));
mBinding.rvSticky.setAdapter(mStickyAdapter);
}
}
粘性适配器
public class StickyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemDecoration.StickyHeaderInterface {
private List<MenuItem> listMenuItems;
public StickyAdapter(List<MenuItem> listMenuItems) {
this.listMenuItems = listMenuItems;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context mContext = parent.getContext();
switch (viewType) {
case MenuItem.HEADER_TYPE:
RowListHeaderItemBinding rowListHeaderItemBinding = RowListHeaderItemBinding.
bind(LayoutInflater.from(mContext).inflate(R.layout.row_list_header_item, parent, false));
return new ViewHolderHeader(rowListHeaderItemBinding);
case MenuItem.CHILD_TYPE:
RowListChildItemBinding rowListChildItemBinding = RowListChildItemBinding
.bind(LayoutInflater.from(mContext).inflate(R.layout.row_list_child_item, parent, false));
return new ViewHolderChild(rowListChildItemBinding);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MenuItem menuItem = listMenuItems.get(position);
switch (menuItem.getmType()) {
case MenuItem.HEADER_TYPE:
((ViewHolderHeader) holder).rowListHeaderItemBinding.tvHeaderItem.setText(menuItem.getItemName());
break;
case MenuItem.CHILD_TYPE:
((ViewHolderChild) holder).rowListChildItemBinding.tvChildItem.setText(menuItem.getItemName());
break;
default:
break;
}
}
public static class ViewHolderHeader extends RecyclerView.ViewHolder {
private RowListHeaderItemBinding rowListHeaderItemBinding;
public ViewHolderHeader(RowListHeaderItemBinding rowListHeaderItemBinding) {
super(rowListHeaderItemBinding.getRoot());
this.rowListHeaderItemBinding = rowListHeaderItemBinding;
}
}
public static class ViewHolderChild extends RecyclerView.ViewHolder {
private RowListChildItemBinding rowListChildItemBinding;
public ViewHolderChild(RowListChildItemBinding rowListChildItemBinding) {
super(rowListChildItemBinding.getRoot());
this.rowListChildItemBinding = rowListChildItemBinding;
}
}
@Override
public int getItemCount() {
return listMenuItems.size();
}
@Override
public int getItemViewType(int position) {
if (listMenuItems != null) {
MenuItem menuItem = listMenuItems.get(position);
if (menuItem != null) {
return menuItem.getmType();
}
}
return 0;
}
@Override
public int getHeaderPositionForItem(int itemPosition) {
int headerPosition = 0;
do {
if (this.isHeader(itemPosition)) {
headerPosition = itemPosition;
break;
}
itemPosition -= 1;
} while (itemPosition >= 0);
return headerPosition;
}
@Override
public int getHeaderLayout(int headerPosition) {
return R.layout.row_list_header_item;
}
@Override
public void bindHeaderData(View header, int headerPosition) {
MenuItem menuItem = listMenuItems.get(headerPosition);
TextView tvName = header.findViewById(R.id.tvHeaderItem);
tvName.setText(menuItem.getItemName());
}
@Override
public boolean isHeader(int itemPosition) {
return listMenuItems.get(itemPosition).isHeader();
}
}
物品装饰
public class ItemDecoration extends RecyclerView.ItemDecoration {
private StickyHeaderInterface mListener;
private int mStickyHeaderHeight;
public ItemDecoration(RecyclerView recyclerView, @NonNull StickyHeaderInterface listener) {
mListener = listener;
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
if (motionEvent.getY() <= mStickyHeaderHeight) {
return true;
}
return false;
}
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
View topChild = parent.getChildAt(0);
if (isNull(topChild)) {
return;
}
int topChildPosition = parent.getChildAdapterPosition(topChild);
if (topChildPosition == RecyclerView.NO_POSITION) {
return;
}
View currentHeader = getHeaderViewForItem(topChildPosition, parent);
fixLayoutSize(parent, currentHeader);
int contactPoint = currentHeader.getBottom();
View childInContact = getChildInContact(parent, contactPoint);
if (isNull(childInContact)) {
return;
}
if (mListener.isHeader(parent.getChildAdapterPosition(childInContact))) {
moveHeader(c, currentHeader, childInContact);
return;
}
drawHeader(c, currentHeader);
}
private View getHeaderViewForItem(int itemPosition, RecyclerView parent) {
int headerPosition = mListener.getHeaderPositionForItem(itemPosition);
int layoutResId = mListener.getHeaderLayout(headerPosition);
View header = LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false);
mListener.bindHeaderData(header, headerPosition);
return header;
}
private void drawHeader(Canvas c, View header) {
c.save();
c.translate(0, 0);
header.draw(c);
c.restore();
}
private void moveHeader(Canvas c, View currentHeader, View nextHeader) {
c.save();
c.translate(0, nextHeader.getTop() - currentHeader.getHeight());
currentHeader.draw(c);
c.restore();
}
private View getChildInContact(RecyclerView parent, int contactPoint) {
View childInContact = null;
for (int i = 0; i < parent.getChildCount(); i++) {
View child = parent.getChildAt(i);
if (child.getBottom() > contactPoint) {
if (child.getTop() <= contactPoint) {
childInContact = child;
break;
}
}
}
return childInContact;
}
private void fixLayoutSize(ViewGroup parent, View view) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), view.getLayoutParams().width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), view.getLayoutParams().height);
view.measure(childWidthSpec, childHeightSpec);
view.layout(0, 0, view.getMeasuredWidth(), mStickyHeaderHeight = view.getMeasuredHeight());
}
private boolean isNull(View view) {
return (view == null);
}
public interface StickyHeaderInterface {
int getHeaderPositionForItem(int itemPosition);
int getHeaderLayout(int headerPosition);
void bindHeaderData(View header, int headerPosition);
boolean isHeader(int itemPosition);
}
}
菜单项
public class MenuItem {
public static final int HEADER_TYPE = 0;
public static final int CHILD_TYPE = 1;
private String itemName;
private int mType;
public boolean isHeader;
public MenuItem(String itemName, int type) {
this.itemName = itemName;
this.mType = type;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public int getmType() {
return mType;
}
public void setmType(int mType) {
this.mType = mType;
}
public boolean isHeader() {
return isHeader;
}
public void setHeader(boolean header) {
isHeader = header;
}
}
我已经添加了到目前为止我已经完成的所有代码,任何人都可以弄清楚实际问题是什么?