背景
最近想实现一个控件漂浮在Item上的效果,需要随着List滑动改变漂浮控件的位置。效果如下图:
本文地址:https://blog.csdn.net/Xiong_IT
作者:MichaelX
最开始的2种方案
- 利用Window.addView(),滑动时updatePosition
- 利用RecyclerView.addView(),滑动时改变漂浮控件floatView的layoutParams.margin
第一种,利用Window更新位置稍微复杂点,放弃。
第二种,RecyclerView.addView()报错。
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2876)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2941)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6455)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1134)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
at android.support.v7.widget.RecyclerView$LayoutManager.removeAndRecycleAllViews(RecyclerView.java:9697)
at android.support.v7.widget.RecyclerView.removeAndRecycleViews(RecyclerView.java:1068)
at android.support.v7.widget.RecyclerView.setAdapterInternal(RecyclerView.java:1091)
at android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:1051)
重点:
Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
源码分析
从上述报错log可知,出错位置在
android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:1051)
报错位置在
android.support.v7.widget.RecyclerView$LayoutManager.removeAndRecycleAllViews(RecyclerView.java:9697)
removeAndRecycleAllViews函数代码如下:
public void removeAndRecycleAllViews(Recycler recycler) {
for (int i = getChildCount() - 1; i >= 0; i--) {
final View view = getChildAt(i);
if (!getChildViewHolderInt(view).shouldIgnore()) {
removeAndRecycleViewAt(i, recycler);
}
}
}
当RecyclerView.addView之后,会进入for循环,走到getChildViewHolderInt(view)
函数中,
static ViewHolder getChildViewHolderInt(View child) {
if (child == null) {
return null;
}
return ((LayoutParams) child.getLayoutParams()).mViewHolder;
}
我们知道,floatView是直接添加的,它并没有mViewHolder,所以这一步返回值为null,所以导致错误:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
最后解决
利用RecyclerView的父控件来添加漂浮控件floatView,滑动监听和更新位置的逻辑不变。
如果刚好碰到这样问题的同学也可以试试给floatView设置ViewHolder,/手动滑稽
((ViewGroup)(mRecyclerView.getParent())).addView(floatView);