调用removeViewInternalremoveView 屏幕还是显示被删除界面 的解决方法和源码分析
Posted 薛瑄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调用removeViewInternalremoveView 屏幕还是显示被删除界面 的解决方法和源码分析相关的知识,希望对你有一定的参考价值。
这是在使用Fragmentation时遇到一个问题,在这个库中很多人都遇到这个问题。修改后的源码已经开源
下面把这个问题的核心抽取出来,进行分析。
问题:
1、removeViewInternal 后,屏幕上还是显示那个被删除的布局界面
2、虽然屏幕上显示那个被删除的布局界面,但是可以点击事件可以传递到后面的布局上。
3、使用Layout Inspector,分析布局,显示的也是后面的布局,当前屏幕的布局没有任何数据
如下图:
对应上面的第2点,在登陆界面登陆按钮的位置点击一下,点击事件穿透到后面登陆界面的登陆按钮上了,提示toast
对应上面的第3点
源码分析:
问题的根本原因就是在remove view 的时候,view的动画还没有执行完。
我们从ViewGroup 的函数removeViewInternal 开始分析
/**
* Removes a view during layout. This is useful if in your onLayout() method,
* you need to remove more views.
*
* <p><strong>Note:</strong> do not invoke this method from
* @link #draw(android.graphics.Canvas), @link #onDraw(android.graphics.Canvas),
* @link #dispatchDraw(android.graphics.Canvas) or any related method.</p>
*
* @param view the view to remove from the group
*/
public void removeViewInLayout(View view)
removeViewInternal(view);
private boolean removeViewInternal(View view)
//获取参数view 在viewGroup中mChildren(view 数组)的索引位置
final int index = indexOfChild(view);
if (index >= 0)
//调用函数进行删除操作
removeViewInternal(index, view);
return true;
return false;
private void removeViewInternal(int index, View view)
...省略若干代码.....
//判断当前的view 正在播放,或预定播放的动画
if (view.getAnimation() != null ||
(mTransitioningViews != null && mTransitioningViews.contains(view)))
addDisappearingView(view);
else if (view.mAttachInfo != null)
view.dispatchDetachedFromWindow();
...省略若干代码.....
在removeViewInternal函数中,省略了与这个问题没有关系的代码。
view.getAnimation() 很简单,重点来分析一下mTransitioningViews 是什么意思
// The set of views that are currently being transitioned. This list is used to track views
// being removed that should not actually be removed from the parent yet because they are
// being animated.
private ArrayList<View> mTransitioningViews;
意思就是它是来存储有过渡动画的view的一个数组列表。因为它们已经设置了动画,因此实际上不应该从父视图中删除。
这里的过渡动画指的是布局容器动画(LayoutTransition 官网介绍),通俗的讲,就是在添加、隐藏子view 的时候,有动画效果。
如果有这些动画效果,就会执行addDisappearingView()
/**
* Add a view which is removed from mChildren but still needs animation
*
* @param v View to add
*/
private void addDisappearingView(View v)
ArrayList<View> disappearingChildren = mDisappearingChildren;
if (disappearingChildren == null)
disappearingChildren = mDisappearingChildren = new ArrayList<View>();
disappearingChildren.add(v);
从注释中可以看出,把这些有动画效果的被删除的view,添加到mDisappearingChildren 数组列表中
在下一次调用ViewGroup 的dispatchDraw时,会把mDisappearingChildren 中的view绘制出来
@Override
protected void dispatchDraw(Canvas canvas)
...省略若干代码.....
// Draw any disappearing views that have animations
if (mDisappearingChildren != null)
final ArrayList<View> disappearingChildren = mDisappearingChildren;
final int disappearingCount = disappearingChildren.size() - 1;
// Go backwards -- we may delete as animations finish
for (int i = disappearingCount; i >= 0; i--)
final View child = disappearingChildren.get(i);
//在当前的viewGroup中绘制有动画但是被删除的view
more |= drawChild(canvas, child, drawingTime);
...省略若干代码.....
至此,就知道为什么有些视图remove后,还是会显示出来
解决方法:
知道了原因,解决办法就很简单了,在remove view 之前,确保动画执行完,或者自己手动viewclearAnimation();
以上是关于调用removeViewInternalremoveView 屏幕还是显示被删除界面 的解决方法和源码分析的主要内容,如果未能解决你的问题,请参考以下文章