1

我尝试在不使用外部库的情况下制作粘性 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;
    }
}

我已经添加了到目前为止我已经完成的所有代码,任何人都可以弄清楚实际问题是什么?

4

1 回答 1

0

布尔值 isHeader 始终返回 false ,因此 Header 始终保持为 false ,因此不会将 View 向上推。

主要活动

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, true));

        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child", MenuItem.CHILD_TYPE, false));

        listMenuItem.add(new MenuItem("Header1", MenuItem.HEADER_TYPE, true));

        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child1", MenuItem.CHILD_TYPE, false));


        listMenuItem.add(new MenuItem("Header2", MenuItem.HEADER_TYPE, true));

        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child2", MenuItem.CHILD_TYPE, false));


        listMenuItem.add(new MenuItem("Header3", MenuItem.HEADER_TYPE, true));

        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child3", MenuItem.CHILD_TYPE, false));


        listMenuItem.add(new MenuItem("Header4", MenuItem.HEADER_TYPE, true));

        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));
        listMenuItem.add(new MenuItem("Child4", MenuItem.CHILD_TYPE, false));

        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 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, boolean isHeader) {
        this.itemName = itemName;
        this.mType = type;
        this.isHeader = isHeader;
    }

    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;
    }
}

通过模型类中的布尔值来检查标题数据,解决了我遇到的问题。

于 2019-10-16T07:58:30.660 回答