I have a ScrollView
which holds a series of Views
. I would like to be able to determine if a view is currently visible (if any part of it is curre
public static int getVisiblePercent(View v) {
if (v.isShown()) {
Rect r = new Rect();
v.getGlobalVisibleRect(r);
double sVisible = r.width() * r.height();
double sTotal = v.getWidth() * v.getHeight();
return (int) (100 * sVisible / sTotal);
} else {
return -1;
}
}
Use View#getHitRect
instead of View#getDrawingRect
on the view you're testing. You can use View#getDrawingRect
on the ScrollView
instead of calculating explicitly.
Code from View#getDrawingRect
:
public void getDrawingRect(Rect outRect) {
outRect.left = mScrollX;
outRect.top = mScrollY;
outRect.right = mScrollX + (mRight - mLeft);
outRect.bottom = mScrollY + (mBottom - mTop);
}
Code from View#getHitRect
:
public void getHitRect(Rect outRect) {
outRect.set(mLeft, mTop, mRight, mBottom);
}
This works:
Rect scrollBounds = new Rect();
scrollView.getHitRect(scrollBounds);
if (imageView.getLocalVisibleRect(scrollBounds)) {
// Any portion of the imageView, even a single pixel, is within the visible window
} else {
// NONE of the imageView is within the visible window
}
If you want to detect that the view is FULLY visible:
private boolean isViewVisible(View view) {
Rect scrollBounds = new Rect();
mScrollView.getDrawingRect(scrollBounds);
float top = view.getY();
float bottom = top + view.getHeight();
if (scrollBounds.top < top && scrollBounds.bottom > bottom) {
return true;
} else {
return false;
}
}
View
is fully visible
, try with this method:private boolean isViewVisible(View view) {
Rect scrollBounds = new Rect();
mScrollView.getDrawingRect(scrollBounds);
float top = view.getY();
float bottom = top + view.getHeight();
if (scrollBounds.top < top && scrollBounds.bottom > bottom) {
return true; //View is visible.
} else {
return false; //View is NOT visible.
}
}
if (myView.getVisibility() == View.VISIBLE) {
//VISIBLE
} else {
//INVISIBLE
}
The posible constant values of the visibility in a View are:
VISIBLE This view is visible. Use with setVisibility(int) and android:visibility.
INVISIBLE This view is invisible, but it still takes up space for layout purposes. Use with setVisibility(int) and android:visibility.
GONE This view is invisible, and it doesn't take any space for layout purposes. Use with setVisibility(int) and android:visibility.
I ended up implementing a combination of two of the Java answers ( @bill-mote https://stackoverflow.com/a/12428154/3686125 and @denys-vasylenko https://stackoverflow.com/a/25528434/3686125 ) in my project as a set of Kotlin extensions, which support either standard vertial ScrollView or HorizontalScrollView controls.
I just tossed these in a Kotlin file named Extensions.kt, no class, just methods.
I used these to determine which item to snap to when a user stops scrolling in various scrollviews in my project:
fun View.isPartiallyOrFullyVisible(horizontalScrollView: HorizontalScrollView) : Boolean {
val scrollBounds = Rect()
horizontalScrollView.getHitRect(scrollBounds)
return getLocalVisibleRect(scrollBounds)
}
fun View.isPartiallyOrFullyVisible(scrollView: ScrollView) : Boolean {
val scrollBounds = Rect()
scrollView.getHitRect(scrollBounds)
return getLocalVisibleRect(scrollBounds)
}
fun View.isFullyVisible(horizontalScrollView: HorizontalScrollView) : Boolean {
val scrollBounds = Rect()
horizontalScrollView.getDrawingRect(scrollBounds)
val left = x
val right = left + width
return scrollBounds.left < left && scrollBounds.right > right
}
fun View.isFullyVisible(scrollView: ScrollView) : Boolean {
val scrollBounds = Rect()
scrollView.getDrawingRect(scrollBounds)
val top = y
val bottom = top + height
return scrollBounds.top < top && scrollBounds.bottom > bottom
}
fun View.isPartiallyVisible(horizontalScrollView: HorizontalScrollView) : Boolean = isPartiallyOrFullyVisible(horizontalScrollView) && !isFullyVisible(horizontalScrollView)
fun View.isPartiallyVisible(scrollView: ScrollView) : Boolean = isPartiallyOrFullyVisible(scrollView) && !isFullyVisible(scrollView)
Example usage, iterating through scrollview's LinearLayout children and logging outputs:
val linearLayoutChild: LinearLayout = getChildAt(0) as LinearLayout
val scrollView = findViewById(R.id.scroll_view) //Replace with your scrollview control or synthetic accessor
for (i in 0 until linearLayoutChild.childCount) {
with (linearLayoutChild.getChildAt(i)) {
Log.d("ScrollView", "child$i left=$left width=$width isPartiallyOrFullyVisible=${isPartiallyOrFullyVisible(scrollView)} isFullyVisible=${isFullyVisible(scrollView)} isPartiallyVisible=${isPartiallyVisible(scrollView)}")
}
}