Android: how to check if a View inside of ScrollView is visible?

后端 未结 14 1900
自闭症患者
自闭症患者 2020-11-22 16:42

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

相关标签:
14条回答
  • 2020-11-22 17:21
    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;
            }
        }
    
    0 讨论(0)
  • 2020-11-22 17:22

    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);
    }
    
    0 讨论(0)
  • 2020-11-22 17:26

    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
    }
    
    0 讨论(0)
  • 2020-11-22 17:29

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-22 17:29

    I you want to detect if your 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.
        }
    }
    

    Strictly speaking you can get the visibility of a view with:

    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.

    0 讨论(0)
  • 2020-11-22 17:31

    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)}")
        }
    }
    
    0 讨论(0)
提交回复
热议问题