14

I have a UIScrollView's paging enabled and set its clipToBounds = NO so that I can see outside current page.

What I want is to enable the user to scroll the UIScrollView on its entire visible area, not only the part of current page.

How can I implement this?

P.S. According to Apple's documentation (https://developer.apple.com/documentation/uikit/uiscrollview), if the value of pagingEnabled property is YES, the scroll view stops on multiples of the scroll view’s bounds when the user scrolls.

This means I cannot just resize the UIScrollView to get what I want without compromising paging functionality, right?

Cœur
  • 37,241
  • 25
  • 195
  • 267
AKFish
  • 305
  • 1
  • 3
  • 7

3 Answers3

14

Put the scrollview into a uiview and disable clipsToBounds of the scrollview. the scrollview must be the size you want for paging. you will see the content outside of the scrollview but paging wil still be the same. You can activate clipsToBounce for the outside view to limit the size of the scrollview.

Overwrite the hitTest of the view to redirect the touches to the scrollview... then you will be able to also scroll by touching outside of the scrollview.

Bastian
  • 10,403
  • 1
  • 31
  • 40
  • 1
    Using your answer, I managed to fix my issue and in the process, I ended up with this simple class to automate such behavior whenever I want. Whenever I need to expand the touch area of a view without changing its frame, I wrap it with a view that has a wider frame and set that view's class to this one I wrote, it works without any further tweaks. https://gist.github.com/diegoperini/8dfa345fca7c733c411dbec6e93729b0 – diegoperini Apr 25 '17 at 14:15
  • This answer is really wrong. It's trivial, and commonplace, to expand the touch-scroll area of a table view or other scroll view. You simply put the extra area desired in the hitTest call. Couldn't be easier. – Fattie Sep 09 '19 at 16:51
  • @Fattie: no this answer is correct. you just don't understand which problem the asking person had in 2011. – Bastian Sep 16 '19 at 13:57
  • howdy B - hmm, (1) "my" solution so to speak (it's just the "everyday solution") entirely respects paging. (Sure, you of course turn off clip if you wish to "see the extra parts".) (2) it's totally possible that as you say, I misunderstand the question and you and/or the OP understand the question better! After all you're more familiar with the decade of existence of the question! :) (3) for this reason I won't delete my seemingly harsh comment, just so that folks can follow along. Thanks for your attention. – Fattie Sep 16 '19 at 14:17
7

Why don't you resize your scrollView so it'll fit the area you need?

Not sure if it'll help, but try to override UIScrollView pointInside method

- (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGRect newBounds = self.bounds;
    newBounds = CGRectInset(bounds, 0, -100.0f);
    return CGRectContainsPoint(newBounds, point);
}
Bastian
  • 10,403
  • 1
  • 31
  • 40
Evgeny Shurakov
  • 6,062
  • 2
  • 28
  • 22
  • My understanding is that the UIScrollView will use its size to calculate the paging, so resizing it will compromise the paging functionality. Thanks anyway. – AKFish Aug 07 '11 at 13:59
  • You can increase contentSize accordingly and correct subviews positions. – Evgeny Shurakov Aug 07 '11 at 14:09
  • Already tried. And getting the contentSize right is essential for paging. My testing result is that the UIScrollView will only response to the touch events inside the bounding area of its frame, and the contentSize has no effect on this issue at all. – AKFish Aug 07 '11 at 14:18
  • 3
    Overriding pointInside:withEvent: on the scroll view to include everything within the superview's bounds worked for me. – Niels Sep 17 '13 at 11:20
  • Note that the comment by @EvgenyShurakov is incorrect and should perhaps be deleted. The answer given here ***is the correct answer***, and you ***do not have to adjust anything***. (The very old comment sby AKFish are utterly, totally incorrect: hit test has no connection whatsoever to "paging" and hit test has utterly no connection to "size". It's totally commonplace to increase the touch size of a scroll view (often due to borders, etc) and you simply do it as shown in this answer. Paging, etc, is totally unaffected. – Fattie Sep 09 '19 at 16:50
  • @fattie: the question was not only about extending the hittest but also about extending the area where the content of the scrollview is shown. This is why I suggested embedding the scrollview into an other view and disabling `cliptobounds`... this way the outer view limits the display of the scrolling pages, while the paging stays the size of the inner scrollview. – Bastian Sep 16 '19 at 13:54
  • the important part here was about extending the display size and size of hittest without affecting the paging size in an UIScrollView. I don't have an idea how code about a UICollectionView would help here. – Bastian Sep 16 '19 at 14:01
  • Just BTW in general I also highly recommend "embedding in another..." as the solid and sensible solution to many of these type of problems in iOS. Just to repeat myself from above, unless I misunderstand something - entirely possible! - this "usual trick" affects neither paging nor visible area (ie, totally OK to turn off clipping). Cheers! – Fattie Sep 16 '19 at 14:23
  • Well nowadays the better solution for this problem would be a collectionview .. but that was not available at this time – Bastian Sep 17 '19 at 07:34
1

2019 syntax example:

class LargerScrollArea: UICollectionView {

    // Example, say this is the left half of the screen, but, we wish to be
    // able to scroll on the whole width of the screen

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        if isUserInteractionEnabled == false { return nil }

        let extraOnRight = bounds.width
        let largerBounds = bounds.inset(by:
                UIEdgeInsets(top: 0, left: 0, bottom:0, right: -extraOnRight))
        if largerBounds.contains(point) {
            return self
        }
        else {
            return nil
        }
    }
}

(Collection view, table view, all the same.)

Fattie
  • 27,874
  • 70
  • 431
  • 719