# Ceiling **Repository Path**: chinasoft6_ohos/ceiling ## Basic Information - **Project Name**: Ceiling - **Description**: No description available - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-11 - **Last Updated**: 2021-08-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 鸿蒙吸顶效果 #### 简单介绍 在安卓中有很多吸顶效果的帖子,但是鸿蒙中暂时还没有,所以就写了个使用ListContainer实现的吸顶效果。 效果如下: ![image text](demo.gif) #### 核心逻辑 1、该吸顶效果,使用了两个ListContainer,底部ListContainer正常显示,顶部的左上角也有个ListContainer用来显示固定的Header。 2、假设顶部ListContainer命名为TopLayout,底部ListContainer命名为BottomLayout。 3、如果TopLayout的底部Y坐标大于BottomLayout中Header部分顶部Y坐标,则BottomLayout会拖动TopLayout滑动。 4、由于快速滑动时候,可能TopLayout与BottomLayout会出现偏差,所以当BottomLayout滑动过后,TopLayout进行归位,保证item在中间部位。 ####具体代码 1、设置回调 ```java public void setStickyListener(StickyListener stickyListener) { this.stickyListener = stickyListener; } ``` 2、BaseItemProvider中构造方面中进行预处理,生成顶部ListContainer。 ```java public void handleList(ListContainer listContainer) { this.downListContainer = listContainer; if (listContainer == null) return; StackLayout stackLayout = new StackLayout(listContainer.getContext()); stackLayout.setLayoutConfig(listContainer.getLayoutConfig()); upListContainer = new ListContainer(listContainer.getContext()); upListContainer.setEnabled(false); listContainer.setLayoutRefreshedListener(component -> { ComponentContainer.LayoutConfig layoutConfig = upListContainer.getLayoutConfig(); //获取第一个Head的索引 int visibleStartIndex = downListContainer.getItemPosByVisibleIndex(0); int i = visibleStartIndex; for (; i < visibleStartIndex + downListContainer.getVisibleIndexCount(); i++) { if (stickyListener != null && !stickyListener.isStickyItemHide(providerList.get(i))) break; } if (i == visibleStartIndex + downListContainer.getVisibleIndexCount()) return; Component tmp = listContainer.getComponentAt(i); if (layoutConfig.width != tmp.getWidth() || layoutConfig.height != tmp.getHeight()) { upListContainer.setLayoutConfig(new ComponentContainer.LayoutConfig( tmp.getWidth(), tmp.getHeight())); itemChange(); } }); ComponentParent componentParent = listContainer.getComponentParent(); int index = componentParent.getChildIndex(listContainer); componentParent.removeComponent(listContainer); ((ComponentContainer) componentParent).addComponent(stackLayout, index); stackLayout.addComponent(listContainer); stackLayout.addComponent(upListContainer); listContainer.addScrolledListener((component, i, i1, i2, i3) -> { if (isUpScroll()) { upContainerScrollY = upContainerScrollY + i1 - i3; upListContainer.scrollTo(0, upContainerScrollY); } else { upContainerHoming(); } }); } ``` 3、初始化布局 ```java public void itemChange() { if (stickyListener == null) return; List tmpList = new ArrayList<>(providerList); Iterator it = tmpList.iterator(); while (it.hasNext()) { if (stickyListener.isStickyItemHide(it.next())) { it.remove(); } } BaseProvider provider = new BaseProvider(context, null, tmpList, layoutId); provider.setComponentBindingListener(new ComponentBindingListener() { @Override public StickyViewHolder creatViewHolder(Component item) { if (componentBindingListener == null) return new StickyViewHolder(item); else return componentBindingListener.creatViewHolder(item); } @Override public void initData(StickyViewHolder viewHolder, StickyBean object, int position) { if (componentBindingListener != null) componentBindingListener.initData(viewHolder, object, position); } }); upListContainer.setItemProvider(provider); } ``` 4、顶部ListContainer是否跟随底部ListContainer进行滑动 ```java public boolean isUpScroll() { float upContainerHeight = upListContainer.getHeight(); int visibleStartIndex = downListContainer.getItemPosByVisibleIndex(0); for (int i = visibleStartIndex; i < visibleStartIndex + downListContainer.getVisibleIndexCount(); i++) { if (stickyListener != null && !stickyListener.isStickyItemHide(providerList.get(i))) { float downHeadTopY = downListContainer.getComponentAt(i).getContentPositionY(); if (upContainerHeight >= downHeadTopY && downHeadTopY > 0) return true; } } return false; } ``` 5、顶部Container滑动完后,进行归位 ```java public void upContainerHoming() { int downIndex = downListContainer.getItemPosByVisibleIndex(0); int downHeadIndex = -1; for (int i = 0; i <= downIndex; i++) { if (stickyListener != null && !stickyListener.isStickyItemHide(providerList.get(i))) { downHeadIndex++; } } if (downHeadIndex == -1) downHeadIndex = 0; //顶部Container进行对齐 upListContainer.getItemProvider().notifyDataChanged(); upContainerScrollY = downHeadIndex * upListContainer.getHeight(); upListContainer.scrollTo(0, upContainerScrollY); } ``` 6、设置回调 ```java public interface ComponentBindingListener { StickyViewHolder creatViewHolder(Component item); void initData(StickyViewHolder viewHolder, StickyBean object, int position); } public interface StickyListener { boolean isStickyItemHide(Object object); } ``` #### 结尾 吸顶效果的核心逻辑已经完成,还有不太理解或者需要的小伙伴,可以选择demo详细查看。 下载地址如下: https://gitee.com/chinasoft6_ohos/ceiling