[android]bug: view remove后仍可见

探讨Android中一个奇特的Bug,即已从父布局中移除的view在某些情况下仍可见。此现象与PullToRefreshView组件的动画实现有关,即使view已被移除,其动画效果仍可能覆盖在其他view上。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android一个view被remove后还能被看到的神奇bug

这是一个神奇的bug(巨大的坑)

最近使用工友封装的一个list控件,发现在下拉刷新失败时会发生两个view重叠的现象,大概是这样:
在这里插入图片描述
一开始以为很简单,就是两个view同时显示出来了。瞬间感觉这位工友封装的控件居然犯了这么低级的错误。然后信心满满滴去寻找让两个view一起set visible的代码。
然而,追踪发现,那个recyclerView明明已经从父布局中remove掉了的。
通过uiautomatorviewer打开这个页面的view结构(如上图右侧),可以明显看到,这个layout里面只包含了中间那个网络异常的提示view,并没有这个recyclerView。
第一次遇到view已经不存在了,但却依然显示在哪里。瞬间石化。这还怎么查?看来android开发这活真的是没法干了?。

直接从分析结论说

当然肯定经过哥艰苦的debug过程,这个问题产生的根本原因如下。
首先这个recyclerView引用了github上一个比较好用的下拉刷新控件PullToRefreshView (https://github.com/Yalantis/Phoenix)来实现下拉刷新的效果。

<PullToRefreshView
        android:id="@+id/list_container">
	<RecyclerView
		android:id="@+id/recycler_list"/>
</PullToRefreshView>

这个问题就出在这个控件的下拉刷新这个实现方式,是用的比较老旧的补间动画。而我们这个项目因为要做一个刷新时如果出现失败就隐藏list,并展示一个失败提示view如上图。然后我的工友使用的办法是在外面在套一层layout:

<RelativeLayout
		......>
	<PullToRefreshView
		    android:id="@+id/list_container">
		<RecyclerView
		    android:id="@+id/recycler_list"
		/>
	</PullToRefreshView>

	<LinearLayout
		    android:id="@+id/load_error_view">
		    <......>
	</LinearLayout>
		
</RelativeLayout>

正常情况,显示list。加载失败时从父layout里remove掉这个PullToRefreshView,add进来那个load_error_view。
就这样,因为PullToRefreshView在加载失败时会从下拉状态向上弹回去,这个动画效果是用Animation补间动画来完成的。
虽然向上弹回之前,就已经调用parentLayout.remove(pullToRefreshView)把这个view移除了。但可能这个动画过程还是要在canvas上绘制,就盖在了load_error_view上面了。
这个是PullToRefreshView弹回动画的代码:

    private void animateOffsetToStartPosition() {
        mFrom = mCurrentOffsetTop;
        mFromDragPercent = mCurrentDragPercent;
        long animationDuration = Math.abs((long) (MAX_OFFSET_ANIMATION_DURATION * mFromDragPercent));
        mAnimateToStartPosition.reset();
        mAnimateToStartPosition.setDuration(animationDuration);
        mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
        mAnimateToStartPosition.setAnimationListener(mToStartListener);
        mRefreshView.clearAnimation();
        mRefreshView.startAnimation(mAnimateToStartPosition);
    }

解决办法

找到问题的根源后,有以下解决思路:
1.不直接解决。如果已经有内容,重新加载失败只简单toast提示。事实上,这样的行为本身就是bug,必须改掉。
这样问题解决大半,但后来发现还是有其他奇奇怪怪的现象。比如多刷新几次,list里面的view颜色会变深之类的。所以还得从根源解决。
2.就算一开始没有内容,加载失败的基本显示行为,也不用add、remove这种方式,直接用setVisibility。
3.在某些场景确实要隐藏list,显示其他提示的时候,先把list的数据清空,让recycler本来就变得没有数据显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值