Android: วิธีตรวจสอบว่าสามารถมองเห็นวิวด้านในของ ScrollView ได้หรือไม่


168

ฉันมีซึ่งถือชุดของScrollView Viewsฉันต้องการทราบว่าขณะนี้มุมมองมองเห็นได้หรือไม่ (หากส่วนใดส่วนหนึ่งของมุมมองนั้นแสดงโดยScrollView) ฉันคาดหวังว่ารหัสด้านล่างเพื่อทำสิ่งนี้ไม่น่าแปลกใจที่:

Rect bounds = new Rect();
view.getDrawingRect(bounds);

Rect scrollBounds = new Rect(scroll.getScrollX(), scroll.getScrollY(), 
        scroll.getScrollX() + scroll.getWidth(), scroll.getScrollY() + scroll.getHeight());

if(Rect.intersects(scrollBounds, bounds))
{
    //is  visible
}

ฉันอยากรู้ว่าคุณจะทำให้สิ่งนี้ทำงานได้อย่างไร ฉันกำลังพยายามทำสิ่งเดียวกัน แต่ ScrollView สามารถโฮสต์เด็ก 1 คนโดยตรงได้เท่านั้น "ซีรี่ย์การดู" ของคุณถูกห่อในเลย์เอาต์อื่นภายใน ScrollView หรือไม่ นั่นคือวิธีการวางของฉัน แต่เมื่อฉันทำอย่างนั้นไม่มีคำตอบที่ให้ไว้ที่นี่ใช้ได้สำหรับฉัน
Rooster242

1
ใช่ชุดการดูของฉันอยู่ใน LinearLayout ซึ่งเป็นลูกที่ 1 ของ ScrollView คำตอบของ Qberticus นั้นใช้ได้กับฉัน
ab11

คำตอบ:


65

ใช้View#getHitRectแทนView#getDrawingRectในมุมมองที่คุณกำลังทดสอบ คุณสามารถใช้View#getDrawingRectบนScrollViewแทนการคำนวณอย่างชัดเจน

รหัสจากView#getDrawingRect:

 public void getDrawingRect(Rect outRect) {
        outRect.left = mScrollX;
        outRect.top = mScrollY;
        outRect.right = mScrollX + (mRight - mLeft);
        outRect.bottom = mScrollY + (mBottom - mTop);
 }

รหัสจากView#getHitRect:

public void getHitRect(Rect outRect) {
        outRect.set(mLeft, mTop, mRight, mBottom);
}

35
ฉันจะเรียกวิธีนี้ได้ที่ไหน
Tooto

3
@Qberticus วิธีการเรียกวิธีการ? ฉันใช้มันและมันก็กลับเท็จเสมอ โปรดแจ้งให้เราทราบ
KK_07k11A0585

2
ตรงไหนที่จะเรียกวิธีการเหล่านี้?
zemaitis

193

งานนี้:

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
}

1
ทำงานได้อย่างสมบูรณ์แบบ วิธีทำให้ชัดเจนยิ่งขึ้น: ส่งคืนค่าจริงหากมุมมองมองเห็นได้ทั้งหมดหรือบางส่วน false หมายความว่ามุมมองนั้นไม่สามารถมองเห็นได้อย่างสมบูรณ์
qwertzguy

1
[1] ผมใช้รหัสนี้จะได้รับGridView/ ListView/ การทำงานร่วมกับGridViewWithHeader SwipeRefreshLayout
Kartik

ใครช่วยอธิบายหน่อยได้ไหมว่าทำไมสิ่งนี้ถึงได้ผล getHitRectคืนค่า rect ในพิกัดพาเรนต์ แต่getLocalVisibleRectคืนค่า rect ในพิกัดโลคอลของ scrollview ใช่ไหม
Pin

3
สิ่งนี้จะไม่ครอบคลุมการซ้อนทับหากมุมมองเด็กซ้อนทับโดยองค์ประกอบย่อยอีกรายการหนึ่งมันจะยังคงกลับมาจริง
Pradeep

1
ใช่เราต้องการอินสแตนซ์ของ Rect.But แต่จำเป็นต้องมี getHitRect มีความแตกต่างหรือไม่ถ้าฉันใช้ Rect (0,0-0,0) เราสามารถเห็นการเรียก getLocalVisibleRect getGlobalVisibleRect และ Rect ถูกตั้งค่าไว้ที่ r.set (0, 0, ความกว้าง, ความสูง); @ BillMote
chefish

56

หากคุณต้องการตรวจสอบว่ามุมมองที่มองเห็นอย่างเต็มที่ :

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;
    }
}

6
นี่คือคำตอบที่ถูกต้อง =) ในกรณีของฉันฉันเปลี่ยน if ดังนี้: scrollBounds.top <= top && scrollBounds.bottom => bottom
Helton Isac

2
+1 Helton หากมุมมองของคุณถูกผลักไปด้านบนหรือด้านล่างสำหรับมุมมองเลื่อนของคุณคุณจะต้อง <= หรือ> = ตามลำดับ
Joe Maher

คุณเคยทดสอบสิ่งนี้จริงเหรอ? มันจะส่งกลับค่า false ในเลย์เอาต์ที่ง่ายที่สุด ScrollView และ TextView แบบเด็ก ๆ
Farid

1
getHitRect () และ getDrawingRect () ต่างกันอย่างไร โปรดให้คำแนะนำ
VVB

2
รหัสนี้ใช้งานได้เฉพาะเมื่อเพิ่มมุมมองลงในรูทของคอนเทนเนอร์ ScrollView โดยตรง ตรวจสอบคำตอบของ Phan Van Linh หากคุณต้องการจัดการมุมมองเด็กในมุมมองเด็กเป็นต้น
thijsonline

12

โซลูชันของฉันใช้NestedScrollViewองค์ประกอบเลื่อน:

    final Rect scrollBounds = new Rect();
    scroller.getHitRect(scrollBounds);

    scroller.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {

            if (myBtn1 != null) {

                if (myBtn1.getLocalVisibleRect(scrollBounds)) {
                    if (!myBtn1.getLocalVisibleRect(scrollBounds)
                            || scrollBounds.height() < myBtn1.getHeight()) {
                        Log.i(TAG, "BTN APPEAR PARCIALY");
                    } else {
                        Log.i(TAG, "BTN APPEAR FULLY!!!");
                    }
                } else {
                    Log.i(TAG, "No");
                }
            }

        }
    });
}

ต้องใช้ API 23+
SolidSnake

@SolidSnake ไม่ต้องนำเข้าคลาสอื่น ๆ ใช้งานได้ดี
Parth Anjaria

10

ในการขยายคำตอบของ Bill Mote โดยใช้ getLocalVisibleRect คุณอาจต้องการตรวจสอบว่ามุมมองนั้นมองเห็นได้เพียงบางส่วนเท่านั้น:

Rect scrollBounds = new Rect();
scrollView.getHitRect(scrollBounds);
if (!imageView.getLocalVisibleRect(scrollBounds)
    || scrollBounds.height() < imageView.getHeight()) {
    // imageView is not within or only partially within the visible window
} else {
    // imageView is completely visible
}

6
สิ่งนี้ไม่ทำงาน .. แม้จะมีการจัดหมวดหมู่มุมมองที่มองเห็นได้บางส่วนให้เห็นอย่างสมบูรณ์
azfar

10

ส่วนขยายนี้ช่วยตรวจจับมุมมองที่มองเห็นได้อย่างสมบูรณ์
นอกจากนี้ยังสามารถใช้งานได้ถ้าคุณViewเป็นลูกของ ... ของScrollView(เช่น: ScrollView-> LinearLayout-> ContraintLayout-> -> ... -> YourView)

fun ScrollView.isViewVisible(view: View): Boolean {
    val scrollBounds = Rect()
    this.getDrawingRect(scrollBounds)
    var top = 0f
    var temp = view
    while (temp !is ScrollView){
        top += (temp).y
        temp = temp.parent as View
    }
    val bottom = top + view.height
    return scrollBounds.top < top && scrollBounds.bottom > bottom
}

บันทึก

1) view.getY()และview.getX()กลับ x, y ที่คุ้มค่าให้กับผู้ปกครองครั้งแรก

2) นี่คือตัวอย่างเกี่ยวกับวิธีการgetDrawingRectคืน ลิงค์ป้อนคำอธิบายรูปภาพที่นี่


ฉันต้องการโซลูชันที่เมธอดควรส่งคืนค่าเท็จหากมุมมองถูกซ่อนอยู่ภายใต้แป้นพิมพ์และใช้งานได้ ขอบคุณ
ราหุล

8
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;
        }
    }

2
สิ่งนี้แตกต่างจากสิ่งที่ ab11 ร้องขอ isShown () ตรวจสอบเฉพาะธงการมองเห็นไม่ใช่มุมมองที่อยู่ในพื้นที่ที่มองเห็นได้ของหน้าจอ
Romain Guy

4
@Romain Guy รหัสไม่ครอบคลุมเมื่อมุมมองทั้งหมดถูกเลื่อนออกไปจากหน้าจอมันควรจะเป็น `static int int getVisiblePercent สาธารณะ (ดู v) {ถ้า (v.isShown ()) {Rect r = new Rect (); boolean isVisible = v.getGlobalVisibleRect (r); ถ้า (isVisible) {double sVisible = r.width () * r.height (); double sTotal = v.getWidth () * v.getHeight (); ผลตอบแทน (int) (100 * sVisible / sTotal); } else {return -1; }} else {return -1; }} `
chefish

6

วันนี้ฉันประสบปัญหาเดียวกัน ในขณะที่ Googling และอ่านการอ้างอิง Android ฉันพบโพสต์นี้และวิธีการที่ฉันใช้แทน;

public final boolean getLocalVisibleRect (Rect r)

นิสัยดีของพวกเขาไม่เพียง แต่ให้บริการ Rect แต่ยังบูลีนระบุว่าดูได้หรือไม่ ด้านลบวิธีนี้ไม่มีเอกสาร :(


1
สิ่งนี้จะบอกคุณว่ารายการนั้นถูกตั้งค่าเป็นทัศนวิสัยหรือไม่ (จริง) ไม่ได้บอกคุณว่ารายการ "มองเห็นได้" นั้นมองเห็นได้จริงภายในวิวพอร์ตหรือไม่
Bill Mote

รหัสสำหรับ getLocalVisibleRect ไม่สนับสนุนการอ้างสิทธิ์ของคุณ: `บูลีนสุดท้ายสาธารณะ getLocalVisibleRect (Rect r) {ออฟเซ็ตจุดสุดท้าย = mAttachInfo! = null? mAttachInfo.mPoint: new Point (); if (getGlobalVisibleRect (r, offset)) {r.offset (-offset.x, -offset.y); // ทำให้ผลตอบแทนในท้องถิ่นเป็นจริง } คืนค่าเท็จ } `
mbafford

6

ฉันต้องการตรวจสอบว่าคุณViewเป็นอย่างเต็มที่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; //View is visible.
    } else {
        return false; //View is NOT visible.
    }
}

การพูดอย่างเคร่งครัดคุณจะสามารถมองเห็นทัศนวิสัยด้วย:

if (myView.getVisibility() == View.VISIBLE) {
    //VISIBLE
} else {
    //INVISIBLE
}

ค่าคงที่ที่เป็นไปได้ของการมองเห็นในมุมมองคือ:

มองเห็นได้ มุมมองนี้จะมองเห็นได้ ใช้กับ setVisibility (int) และ android: การมองเห็น

มองไม่เห็น มุมมองนี้มองไม่เห็น แต่ยังคงใช้พื้นที่สำหรับการจัดวาง ใช้กับ setVisibility (int) และ android: การมองเห็น

หายไป มุมมองนี้จะมองไม่เห็นและไม่ใช้พื้นที่สำหรับจุดประสงค์ของการจัดวาง ใช้กับ setVisibility (int) และ android: การมองเห็น


3
ปรบมือช้า สิ่งที่ OP ต้องการทราบคือสมมติว่าทัศนวิสัยเป็นมุมมอง # มองเห็นได้อย่างไรจะรู้ได้อย่างไรว่ามุมมองนั้นสามารถมองเห็นได้ในแถบเลื่อน
Joao Sousa

1
ฉันเพิ่งตรวจสอบโครงการง่าย ๆ เค้าโครงมี ScrollView และ TextView เป็นเด็ก ส่งคืนค่าเท็จเสมอแม้ว่า TextView จะปรากฏอย่างสมบูรณ์
Farid

มันกลับเท็จเสมอ
ราหุล

3

คุณสามารถใช้สิ่งFocusAwareScrollViewที่แจ้งเตือนเมื่อมองเห็นได้:

FocusAwareScrollView focusAwareScrollView = (FocusAwareScrollView) findViewById(R.id.focusAwareScrollView);
    if (focusAwareScrollView != null) {

        ArrayList<View> viewList = new ArrayList<>();
        viewList.add(yourView1);
        viewList.add(yourView2);

        focusAwareScrollView.registerViewSeenCallBack(viewList, new FocusAwareScrollView.OnViewSeenListener() {

            @Override
            public void onViewSeen(View v, int percentageScrolled) {

                if (v == yourView1) {

                    // user have seen view1

                } else if (v == yourView2) {

                    // user have seen view2
                }
            }
        });

    }

นี่คือคลาส:

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class FocusAwareScrollView extends NestedScrollView {

    private List<OnScrollViewListener> onScrollViewListeners = new ArrayList<>();

    public FocusAwareScrollView(Context context) {
        super(context);
    }

    public FocusAwareScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusAwareScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public interface OnScrollViewListener {
        void onScrollChanged(FocusAwareScrollView v, int l, int t, int oldl, int oldt);
    }

    public interface OnViewSeenListener {
        void onViewSeen(View v, int percentageScrolled);
    }

    public void addOnScrollListener(OnScrollViewListener l) {
        onScrollViewListeners.add(l);
    }

    public void removeOnScrollListener(OnScrollViewListener l) {
        onScrollViewListeners.remove(l);
    }

    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        for (int i = onScrollViewListeners.size() - 1; i >= 0; i--) {
            onScrollViewListeners.get(i).onScrollChanged(this, l, t, oldl, oldt);
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    public void requestChildFocus(View child, View focused) {
        super.requestChildFocus(child, focused);
    }

    private boolean handleViewSeenEvent(View view, int scrollBoundsBottom, int scrollYOffset,
                                        float minSeenPercentage, OnViewSeenListener onViewSeenListener) {
        int loc[] = new int[2];
        view.getLocationOnScreen(loc);
        int viewBottomPos = loc[1] - scrollYOffset + (int) (minSeenPercentage / 100 * view.getMeasuredHeight());
        if (viewBottomPos <= scrollBoundsBottom) {
            int scrollViewHeight = this.getChildAt(0).getHeight();
            int viewPosition = this.getScrollY() + view.getScrollY() + view.getHeight();
            int percentageSeen = (int) ((double) viewPosition / scrollViewHeight * 100);
            onViewSeenListener.onViewSeen(view, percentageSeen);
            return true;
        }
        return false;
    }

    public void registerViewSeenCallBack(final ArrayList<View> views, final OnViewSeenListener onViewSeenListener) {

        final boolean[] viewSeen = new boolean[views.size()];

        FocusAwareScrollView.this.postDelayed(new Runnable() {
            @Override
            public void run() {

                final Rect scrollBounds = new Rect();
                FocusAwareScrollView.this.getHitRect(scrollBounds);
                final int loc[] = new int[2];
                FocusAwareScrollView.this.getLocationOnScreen(loc);

                FocusAwareScrollView.this.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {

                    boolean allViewsSeen = true;

                    @Override
                    public void onScrollChange(NestedScrollView v, int x, int y, int oldx, int oldy) {

                        for (int index = 0; index < views.size(); index++) {

                            //Change this to adjust criteria
                            float viewSeenPercent = 1;

                            if (!viewSeen[index])
                                viewSeen[index] = handleViewSeenEvent(views.get(index), scrollBounds.bottom, loc[1], viewSeenPercent, onViewSeenListener);

                            if (!viewSeen[index])
                                allViewsSeen = false;
                        }

                        //Remove this if you want continuous callbacks
                        if (allViewsSeen)
                            FocusAwareScrollView.this.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) null);
                    }
                });
            }
        }, 500);
    }
}

1

วิธี Kotlin;

ส่วนขยายสำหรับการเลื่อนดูรายการของมุมมองเลื่อนและรับการดำเนินการถ้ามุมมองย่อยปรากฏบนหน้าจอ

@SuppressLint("ClickableViewAccessibility")
fun View.setChildViewOnScreenListener(view: View, action: () -> Unit) {
    val visibleScreen = Rect()

    this.setOnTouchListener { _, motionEvent ->
        if (motionEvent.action == MotionEvent.ACTION_MOVE) {
            this.getDrawingRect(visibleScreen)

            if (view.getLocalVisibleRect(visibleScreen)) {
                action()
            }
        }

        false
    }
}

ใช้ฟังก์ชันส่วนขยายนี้สำหรับมุมมองที่เลื่อนได้

nestedScrollView.setChildViewOnScreenListener(childView) {
               action()
            }

0

ฉันรู้ว่ามันสายมาก แต่ฉันมีทางออกที่ดี ด้านล่างนี้เป็นข้อมูลโค้ดสำหรับรับเปอร์เซ็นต์การมองเห็นในมุมมองเลื่อน

ครั้งแรกของทุกฟังสัมผัสที่ตั้งค่าไว้ในมุมมองเลื่อนสำหรับการโทรกลับเพื่อหยุดเลื่อน

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch ( event.getAction( ) ) {
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if(mScrollView == null){
                        mScrollView = (ScrollView) findViewById(R.id.mScrollView);
                    }
                    int childCount = scrollViewRootChild.getChildCount();

                    //Scroll view location on screen
                    int[] scrollViewLocation = {0,0};
                    mScrollView.getLocationOnScreen(scrollViewLocation);

                    //Scroll view height
                    int scrollViewHeight = mScrollView.getHeight();
                    for (int i = 0; i < childCount; i++){
                        View child = scrollViewRootChild.getChildAt(i);
                        if(child != null && child.getVisibility() == View.VISIBLE){
                            int[] viewLocation = new int[2];
                            child.getLocationOnScreen(viewLocation);
                            int viewHeight = child.getHeight();
                            getViewVisibilityOnScrollStopped(scrollViewLocation, scrollViewHeight,
                                    viewLocation, viewHeight, (String) child.getTag(), (childCount - (i+1)));
                        }
                    }
                }
            }, 150);
            break;
    }
    return false;
}

ในตัวอย่างโค้ดข้างต้นเราได้รับการโทรกลับสำหรับเหตุการณ์การสัมผัสแบบเลื่อนดูและโพสต์ runnable หลังจาก 150 มิลลิวินาที (ไม่บังคับ) หลังจากการเรียกกลับสำหรับการเลื่อนหยุด ใน runnable ที่เราจะได้รับตำแหน่งของมุมมองเลื่อนบนหน้าจอและความสูงมุมมองเลื่อน จากนั้นรับอินสแตนซ์กลุ่มย่อย view view ของ scroll view และรับจำนวนนับ ในกรณีของฉันโดยตรงลูกของมุมมองเลื่อนเป็น LinearLayout ชื่อ scrollViewRootChild แล้วย้ำทุกมุมมองเด็กของscrollViewRootChild ในตัวอย่างโค้ดข้างต้นคุณสามารถเห็นฉันได้รับตำแหน่งของเด็กบนหน้าจอในอาร์เรย์จำนวนเต็มชื่อviewLocationรับความสูงของการดูในชื่อตัวแปรviewHeight viewHeightจากนั้นฉันเรียกว่าเมธอดส่วนตัวgetViewVisibilityOnScrollStopped. คุณสามารถเข้าใจการทำงานภายในของวิธีนี้ได้โดยการอ่านเอกสาร

/**
 * getViewVisibilityOnScrollStopped
 * @param scrollViewLocation location of scroll view on screen
 * @param scrollViewHeight height of scroll view
 * @param viewLocation location of view on screen, you can use the method of view claas's getLocationOnScreen method.
 * @param viewHeight height of view
 * @param tag tag on view
 * @param childPending number of views pending for iteration.
 */
void getViewVisibilityOnScrollStopped(int[] scrollViewLocation, int scrollViewHeight, int[] viewLocation, int viewHeight, String tag, int childPending) {
    float visiblePercent = 0f;
    int viewBottom = viewHeight + viewLocation[1]; //Get the bottom of view.
    if(viewLocation[1] >= scrollViewLocation[1]) {  //if view's top is inside the scroll view.
        visiblePercent = 100;
        int scrollBottom = scrollViewHeight + scrollViewLocation[1];    //Get the bottom of scroll view 
        if (viewBottom >= scrollBottom) {   //If view's bottom is outside from scroll view
            int visiblePart = scrollBottom - viewLocation[1];  //Find the visible part of view by subtracting view's top from scrollview's bottom  
            visiblePercent = (float) visiblePart / viewHeight * 100;
        }
    }else{      //if view's top is outside the scroll view.
        if(viewBottom > scrollViewLocation[1]){ //if view's bottom is outside the scroll view
            int visiblePart = viewBottom - scrollViewLocation[1]; //Find the visible part of view by subtracting scroll view's top from view's bottom
            visiblePercent = (float) visiblePart / viewHeight * 100;
        }
    }
    if(visiblePercent > 0f){
        visibleWidgets.add(tag);        //List of visible view.
    }
    if(childPending == 0){
        //Do after iterating all children.
    }
}

หากคุณรู้สึกว่าการปรับปรุงใด ๆ ในรหัสนี้โปรดช่วย


0

ฉันสิ้นสุดการใช้งานการรวมกันของสองคำตอบ Java (@ bill-mote https://stackoverflow.com/a/12428154/3686125และ @ denys-vasylenko https://stackoverflow.com/a/25528434/3686125 ) ใน โปรเจ็กต์ของฉันเป็นชุดของส่วนขยาย Kotlin ซึ่งรองรับตัวเลื่อนแนวตั้งมาตรฐานแบบ ScrollView หรือแนวนอนScrollView

ฉันเพิ่งโยนสิ่งเหล่านี้ในไฟล์ Kotlin ชื่อ Extensions.kt ไม่มีคลาสวิธีการ

ฉันใช้สิ่งเหล่านี้เพื่อกำหนดว่ารายการใดที่จะ snap เมื่อผู้ใช้หยุดการเลื่อนใน scrollviews ต่างๆในโครงการของฉัน:

fun View.isPartiallyOrFullyVisible(horizontalScrollView: HorizontalScrollView) : Boolean {
    @Suppress("CanBeVal") var scrollBounds = Rect()
    horizontalScrollView.getHitRect(scrollBounds)
    return getLocalVisibleRect(scrollBounds)
}

fun View.isPartiallyOrFullyVisible(scrollView: ScrollView) : Boolean {
    @Suppress("CanBeVal") var scrollBounds = Rect()
    scrollView.getHitRect(scrollBounds)
    return getLocalVisibleRect(scrollBounds)
}

fun View.isFullyVisible(horizontalScrollView: HorizontalScrollView) : Boolean {
    @Suppress("CanBeVal") var 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 {
    @Suppress("CanBeVal") var 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)

ตัวอย่างการใช้งาน, วนซ้ำผ่านลูก ๆ LinearLayout ของ scrollview และเอาต์พุตการบันทึก:

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)}")
    }
}

1
ทำไมคุณใช้varและระงับคำใบ้ IDE?
Filipkowicz

-1

ใช้ @Qberticus คำตอบซึ่งเป็นประเด็น แต่ btw ยอดเยี่ยมฉันได้รวบรวมรหัสเพื่อตรวจสอบว่าเมื่อใดก็ตามที่มีการเรียกใช้ scrollview และเลื่อนไปมันจะเรียก @Qberticus และคุณสามารถทำสิ่งที่คุณต้องการในกรณีของฉัน เครือข่ายโซเชียลที่มีวิดีโอดังนั้นเมื่อมุมมองถูกวาดบนหน้าจอฉันเล่นวิดีโอแนวคิดเดียวกันเช่น Facebook และ Instagram นี่คือรหัส:

mainscrollview.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {

                    @Override
                    public void onScrollChanged() {
                        //mainscrollview is my scrollview that have inside it a linearlayout containing many child views.
                        Rect bounds = new Rect();
                         for(int xx=1;xx<=postslayoutindex;xx++)
                         {

                          //postslayoutindex is the index of how many posts are read.
                          //postslayoutchild is the main layout for the posts.
                        if(postslayoutchild[xx]!=null){

                            postslayoutchild[xx].getHitRect(bounds);

                        Rect scrollBounds = new Rect();
                        mainscrollview.getDrawingRect(scrollBounds);

                        if(Rect.intersects(scrollBounds, bounds))
                        {
                            vidPreview[xx].startPlaywithoutstoppping();
                         //I made my own custom video player using textureview and initialized it globally in the class as an array so I can access it from anywhere.
                        }
                        else
                        {

                        }


                        }
                    }
                    }
                });
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.