Xamarin.Forms:如何判断Android端视图已绘制到屏幕
监听视图的挂载状态
给目标View添加OnAttachStateChangeListener,通过onViewAttachedToWindow和onViewDetachedFromWindow判断视图是否被添加到窗口。但要注意,视图挂载到窗口不代表它一定在屏幕可见(比如被其他View完全遮挡,或者处于ViewPager的非当前页面)。
代码示例:yourTargetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { // 视图已挂载到窗口,可做基础可见性判断 } @Override public void onViewDetachedFromWindow(View v) { // 视图已从窗口移除 } });重写View的窗口可见性回调
自定义View或者给现有View重写onWindowVisibilityChanged方法,当视图所在窗口的可见性变化时触发(比如Activity切到后台、回到前台)。参数visibility为View.VISIBLE时,说明视图所在窗口处于可见状态,但仍需结合视图自身的遮挡情况判断。
代码示例:@Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); if (visibility == View.VISIBLE) { // 视图所在窗口可见,可进一步判断视图是否真的在屏幕上 } else { // 窗口不可见 } }通过ViewTreeObserver判断真实可见区域
如果需要精确判断视图是否有部分/全部在屏幕可见,用ViewTreeObserver结合getGlobalVisibleRect方法。这个方法能获取视图在屏幕坐标系中的可见区域,若区域不为空,说明视图至少有一部分在屏幕上。
代码示例:ViewTreeObserver observer = yourTargetView.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect visibleRect = new Rect(); boolean isVisible = yourTargetView.getGlobalVisibleRect(visibleRect); if (isVisible && !visibleRect.isEmpty()) { // 视图在屏幕可见 } else { // 视图完全不可见 } // 记得移除监听避免内存泄漏,分版本处理 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { yourTargetView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { yourTargetView.getViewTreeObserver().removeGlobalOnLayoutListener(this); } } });如果是滚动场景(比如RecyclerView、ScrollView),可以在滚动监听回调里重复调用
getGlobalVisibleRect来实时判断。结合Jetpack Lifecycle判断
如果你用了Jetpack组件,可以给Activity/Fragment添加LifecycleObserver,监听onResume、onPause等生命周期回调,再结合视图的可见性判断。但要注意,Fragment的onResume不代表它的视图一定在屏幕(比如ViewPager的非当前页Fragment),还是要配合前面的方法做最终判断。关键区分点
别混淆"挂载到窗口"和"可见于屏幕":前者只是视图加入了窗口的视图树,后者才是用户能看到的状态。如果要做精确的可见性触发逻辑,必须用getGlobalVisibleRect这类方法去计算真实可见区域。
内容的提问来源于stack exchange,提问作者Microkid

