From 8423bbfeb7ba37f6d1de882ebd54699d26c9cc84 Mon Sep 17 00:00:00 2001 From: TellH <570495627@qq.com> Date: Thu, 11 May 2017 14:43:25 +0800 Subject: [PATCH] Fix the bug when clearing item. --- .../MainActivity.java | 10 ++- app/src/main/res/menu/menu_main.xml | 4 +- .../stickyheaderview_rv/LinkListStack.java | 42 +++++++++++++ .../stickyheaderview_rv/StickyHeaderView.java | 62 ++++++++++++------- .../adapter/StickyHeaderViewAdapter.java | 49 +++++++++++---- 5 files changed, 126 insertions(+), 41 deletions(-) create mode 100644 stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/LinkListStack.java diff --git a/app/src/main/java/tellh/com/recyclerstickyheaderview/MainActivity.java b/app/src/main/java/tellh/com/recyclerstickyheaderview/MainActivity.java index ba0acc0..ee1d70b 100644 --- a/app/src/main/java/tellh/com/recyclerstickyheaderview/MainActivity.java +++ b/app/src/main/java/tellh/com/recyclerstickyheaderview/MainActivity.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Random; import tellh.com.stickyheaderview_rv.adapter.DataBean; import tellh.com.stickyheaderview_rv.adapter.StickyHeaderViewAdapter; @@ -20,6 +21,7 @@ public class MainActivity extends AppCompatActivity { private RecyclerView rv; private StickyHeaderViewAdapter adapter; + private Random random = new Random(System.currentTimeMillis()); @Override protected void onCreate(Bundle savedInstanceState) { @@ -74,9 +76,11 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add_view: User user = new User("Sticky View", 123, "https://avatars.githubusercontent.com/u/15800681?v=3"); - user.setShouldSticky(true); - adapter.getDisplayList().add(3, user); - adapter.notifyItemInserted(3); + user.setShouldSticky(random.nextBoolean()); + adapter.append(user); + break; + case R.id.action_clear_all: + adapter.clear(rv); break; default: break; diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 8b38acb..56afae3 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,5 +1,5 @@ - + + \ No newline at end of file diff --git a/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/LinkListStack.java b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/LinkListStack.java new file mode 100644 index 0000000..fa32ba6 --- /dev/null +++ b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/LinkListStack.java @@ -0,0 +1,42 @@ +package tellh.com.stickyheaderview_rv; + +import java.util.EmptyStackException; +import java.util.LinkedList; + +/** + * Created by tlh on 2017/5/11 :) + */ + +public class LinkListStack { + private LinkedList list = new LinkedList<>(); + + public E push(E item) { + list.addLast(item); + return item; + } + + public E pop() { + if (list.isEmpty()) + return null; + return list.removeLast(); + } + + public synchronized E peek() { + if (list.size() == 0) + throw new EmptyStackException(); + return list.peekLast(); + } + + public boolean isEmpty() { + return list.size() == 0; + } + + public void clear() { + list.clear(); + } + + public boolean remove(E item) { + return list.remove(item); + } + +} diff --git a/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/StickyHeaderView.java b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/StickyHeaderView.java index b8beb42..477e7b0 100644 --- a/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/StickyHeaderView.java +++ b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/StickyHeaderView.java @@ -11,9 +11,6 @@ import android.view.ViewGroup; import android.widget.FrameLayout; -import java.util.List; -import java.util.Stack; - import tellh.com.stickyheaderview_rv.adapter.DataBean; import tellh.com.stickyheaderview_rv.adapter.StickyHeaderViewAdapter; import tellh.com.stickyheaderview_rv.adapter.ViewBinder; @@ -22,14 +19,15 @@ * Created by tlh on 2017/1/21 :) */ -public class StickyHeaderView extends FrameLayout { +public class StickyHeaderView extends FrameLayout + implements StickyHeaderViewAdapter.DataSetChangeListener { private boolean hasInit = false; private FrameLayout mHeaderContainer; private RecyclerView mRecyclerView; private int mHeaderHeight = -1; private StickyHeaderViewAdapter adapter; private LinearLayoutManager layoutManager; - private Stack stickyHeaderPositionStack = new Stack<>(); + private LinkListStack stickyHeaderStack = new LinkListStack<>(); private SparseArray mViewHolderCache; public StickyHeaderView(Context context) { @@ -70,6 +68,7 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { throw new RuntimeException ("Your RecyclerView.Adapter should be the type of StickyHeaderViewAdapter."); StickyHeaderView.this.adapter = (StickyHeaderViewAdapter) adapter; + StickyHeaderView.this.adapter.setDataSetChangeListener(StickyHeaderView.this); layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); mViewHolderCache = new SparseArray<>(); } /*else if (mHeaderHeight == 0) { @@ -83,17 +82,19 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (mHeaderHeight == -1 || adapter == null || layoutManager == null) return; - List displayList = adapter.getDisplayList(); - if (stickyHeaderPositionStack.isEmpty()) - stickyHeaderPositionStack.push(findFirstVisibleStickyHeaderPosition(displayList, 0)); + if (stickyHeaderStack.isEmpty() && adapter.getDisplayListSize() != 0) + stickyHeaderStack.push(adapter.get(findFirstVisibleStickyHeaderPosition(0))); int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); - int firstVisibleStickyHeaderPosition = findFirstVisibleStickyHeaderPosition(displayList, firstVisibleItemPosition); - int currentStickyHeaderPosition = stickyHeaderPositionStack.peek(); + if (firstVisibleItemPosition == -1) + return; + int firstVisibleStickyHeaderPosition = findFirstVisibleStickyHeaderPosition(firstVisibleItemPosition); + int currentStickyHeaderPosition = adapter.getPosition(stickyHeaderStack.peek()); if (firstVisibleStickyHeaderPosition - firstVisibleItemPosition > 1) { return; } // 如果两个连续两个都是StickyView, 取下面那个View - if (displayList.get(firstVisibleStickyHeaderPosition + 1).shouldSticky()) + DataBean dataBean = adapter.get(firstVisibleStickyHeaderPosition + 1); + if (dataBean != null && dataBean.shouldSticky()) firstVisibleStickyHeaderPosition++; View firstVisibleStickyHeader = layoutManager.findViewByPosition(firstVisibleStickyHeaderPosition); if (firstVisibleStickyHeader == null) @@ -102,20 +103,20 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (headerTop > 0 && headerTop <= mHeaderHeight) { //吸顶正在更替的状态 mHeaderContainer.setY(-(mHeaderHeight - headerTop)); if (firstVisibleStickyHeaderPosition == currentStickyHeaderPosition) { - stickyHeaderPositionStack.pop(); - if (!stickyHeaderPositionStack.isEmpty()) - updateHeaderView(stickyHeaderPositionStack.peek()); + stickyHeaderStack.pop(); + if (!stickyHeaderStack.isEmpty()) + updateHeaderView(stickyHeaderStack.peek()); } } else if (headerTop <= 0) { //吸顶稳定在最上方的状态 mHeaderContainer.setY(0); - updateHeaderView(firstVisibleItemPosition); + updateHeaderView(adapter.get(firstVisibleItemPosition)); } // Cache the StickyHeader position. if (firstVisibleStickyHeaderPosition > currentStickyHeaderPosition) - stickyHeaderPositionStack.push(firstVisibleStickyHeaderPosition); + stickyHeaderStack.push(adapter.get(firstVisibleStickyHeaderPosition)); else if (firstVisibleStickyHeaderPosition < currentStickyHeaderPosition) - stickyHeaderPositionStack.pop(); + stickyHeaderStack.pop(); } } @@ -123,18 +124,17 @@ else if (firstVisibleStickyHeaderPosition < currentStickyHeaderPosition) } - private int findFirstVisibleStickyHeaderPosition(List displayList, int firstVisibleItemPosition) { + private int findFirstVisibleStickyHeaderPosition(int firstVisibleItemPosition) { int i = firstVisibleItemPosition; - for (; i < displayList.size(); i++) { - if (!displayList.get(i).shouldSticky()) + for (; i < adapter.getDisplayListSize(); i++) { + if (!adapter.get(i).shouldSticky()) continue; break; } return i; } - private void updateHeaderView(int position) { - DataBean entity = adapter.getDisplayList().get(position); + private void updateHeaderView(DataBean entity) { int layoutId = entity.getItemLayoutId(adapter); clearHeaderView(); RecyclerView.ViewHolder viewHolder = mViewHolderCache.get(layoutId); @@ -147,9 +147,10 @@ private void updateHeaderView(int position) { } mHeaderContainer.addView(viewHolder.itemView); mHeaderHeight = mHeaderContainer.getHeight(); - headerViewBinder.bindView(adapter, viewHolder, position, entity); + headerViewBinder.bindView(adapter, viewHolder, adapter.getPosition(entity), entity); } + // Remove the Header View private void clearHeaderView() { mHeaderContainer.removeAllViews(); } @@ -160,4 +161,19 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto super.onLayout(changed, left, top, right, bottom); } + @Override + public void onClearAll() { + stickyHeaderStack.clear(); + clearHeaderView(); + } + + @Override + public void remove(int pos) { + DataBean entity = adapter.get(pos); + if (stickyHeaderStack.peek() == entity) + clearHeaderView(); + if (entity != null && entity.shouldSticky()) { + stickyHeaderStack.remove(entity); + } + } } diff --git a/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/adapter/StickyHeaderViewAdapter.java b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/adapter/StickyHeaderViewAdapter.java index 7deee2b..982dadf 100644 --- a/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/adapter/StickyHeaderViewAdapter.java +++ b/stickyheaderview-rv/src/main/java/tellh/com/stickyheaderview_rv/adapter/StickyHeaderViewAdapter.java @@ -8,13 +8,13 @@ import android.view.ViewGroup; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class StickyHeaderViewAdapter extends RecyclerView.Adapter { private static int SIZE_VIEW_BINDER_POOL = 10; private SparseArrayCompat viewBinderPool; protected List displayList; + private DataSetChangeListener onDataSetChangeListener; public StickyHeaderViewAdapter(List displayList) { viewBinderPool = new SparseArrayCompat<>(SIZE_VIEW_BINDER_POOL); @@ -23,10 +23,24 @@ public StickyHeaderViewAdapter(List displayList) { this.displayList.addAll(displayList); } - public List getDisplayList() { + private List getDisplayList() { return displayList; } + public int getDisplayListSize() { + return displayList == null ? 0 : displayList.size(); + } + + public DataBean get(int i) { + if (i < getDisplayListSize()) + return displayList.get(i); + else return null; + } + + public int getPosition(DataBean dataBean) { + return displayList.indexOf(dataBean); + } + @Override public int getItemViewType(int position) { return displayList.get(position).getItemLayoutId(this); @@ -69,37 +83,35 @@ public void clearViewBinderCache() { viewBinderPool.clear(); } - public void addAll(List list) { + public void append(List list) { if (list == null) return; displayList.addAll(list); notifyDataSetChanged(); } + public void append(DataBean dataBean) { + displayList.add(dataBean); + notifyItemInserted(displayList.size() - 1); + } + public void refresh(List list) { if (list == null) return; + onDataSetChangeListener.onClearAll(); displayList.clear(); displayList.addAll(list); notifyDataSetChanged(); } - public void add(int pos, DataBean item) { - displayList.add(pos, item); - notifyItemInserted(pos); - } - public void delete(int pos) { + onDataSetChangeListener.remove(pos); displayList.remove(pos); notifyItemRemoved(pos); } - public void swap(int fromPosition, int toPosition) { - Collections.swap(displayList, fromPosition, toPosition); - notifyItemMoved(fromPosition, toPosition); - } - public void clear(RecyclerView recyclerView) { + onDataSetChangeListener.onClearAll(); displayList.clear(); notifyDataSetChanged(); recyclerView.scrollToPosition(0); @@ -109,4 +121,15 @@ public StickyHeaderViewAdapter RegisterItemType(ViewBinder viewBinder) { viewBinderPool.put(viewBinder.getItemLayoutId(this), viewBinder); return this; } + + // Don't Call this Method + public void setDataSetChangeListener(DataSetChangeListener listener) { + this.onDataSetChangeListener = listener; + } + + public interface DataSetChangeListener { + void onClearAll(); + + void remove(int pos); + } }