adit
adit

Reputation: 33684

check if UIView is in UIScrollView visible state

What is the easiest and most elegant way to check if a UIView is visible on the current UIScrollView's contentView? There are two ways to do this, one is involving the contentOffset.y position of the UIScrollView and the other way is to convert the rect area?

Upvotes: 26

Views: 28268

Answers (8)

Kishlay Kishore
Kishlay Kishore

Reputation: 11

As Soon as screen appears our scrollViewDidScroll delegate got called and all view intersect check inside scroll view will return true, so add a line scrollView.isTracking before our view intersect checks. something like this worked for me.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        if scrollView.isTracking {
            let viewFrame1 = scrollView.convert(targetView.bounds, from: targetView)
            
            if viewFrame1.intersects(scrollView.bounds) {
                //Your Methods Goes Here
            }
        }
    }

Upvotes: 0

Anton Plebanovich
Anton Plebanovich

Reputation: 1526

Solution that takes into account insets

public extension UIScrollView {
    
    /// Returns `adjustedContentInset` on iOS >= 11 and `contentInset` on iOS < 11.
    var fullContentInsets: UIEdgeInsets {
        if #available(iOS 11.0, *) {
            return adjustedContentInset
        } else {
            return contentInset
        }
    }

    /// Visible content frame. Equal to bounds without insets.
    var visibleContentFrame: CGRect {
        bounds.inset(by: fullContentInsets)
    }
}

if scrollView.visibleContentFrame.contains(view) {
    // View is fully visible even if there are overlaying views
}

Upvotes: 2

RyanG
RyanG

Reputation: 4503

José's solution didn't quite work for me, it was detecting my view before it came on screen. The following intersects code works perfect in my tableview if José's simpler solution doesn't work for you.

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let viewFrame = scrollView.convert(targetView.bounds, from: targetView)
        if viewFrame.intersects(scrollView.bounds) {
            // targetView is visible 
        }
        else {
            // targetView is not visible
        }
    }

Upvotes: 3

Jos&#233;
Jos&#233;

Reputation: 3174

Swift 5: in case that you want to trigger an event that checks that the entire UIView is visible in the scroll view:

extension ViewController: UIScrollViewDelegate {

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.bounds.contains(targetView.frame) {
            // entire UIView is visible in scroll view
        }
    }

}

Upvotes: 25

Wesley Schrauwen
Wesley Schrauwen

Reputation: 51

updated for swift 3

var rect1: CGRect!
// initialize rect1 to the relevant subview
if rect1.frame.intersects(CGRect(origin: scrollView.contentOffset, size: scrollView.frame.size)) {
        // the view is visible
    }

Upvotes: 5

Marc
Marc

Reputation: 1541

If you're trying to work out if a view has been scrolled on screen, try this:

    CGRect thePosition =  myView.frame;
    CGRect container = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, scrollView.frame.size.width, scrollView.frame.size.height);
    if(CGRectIntersectsRect(thePosition, container))
    {
        // This view has been scrolled on screen
    }

Upvotes: 23

Omar Abdelhafith
Omar Abdelhafith

Reputation: 21221

I think your ideas are correct. if it was me i would do it as following:

//scrollView is the main scroll view
//mainview is scrollview.superview
//view is the view inside the scroll view

CGRect viewRect = view.frame;
CGRect mainRect = mainView.frame;

if(CGRectIntersectsRect(mainRect, viewRect))
{
    //view is visible
}

Upvotes: 2

Jitendra Singh
Jitendra Singh

Reputation: 2181

Implement scrollViewDidScroll: in your scroll view delegate and calculate manually which views are visible (e.g. by checking if CGRectIntersectsRect(scrollView.bounds, subview.frame) returns true.

Upvotes: 8

Related Questions