iOS 13: UIScrollView no longer scrolls

I have a UIScrollView that contains a UISegmentedControl. The idea is that the user can scroll the segmented control back and forth to view options that fall outside the visible area of the device's screen. The user can also tap on a partially visible selection and it'll scroll to the center of the view. This all worked fine until iOS 13. Now the scroll view won't move via a touch although it does move programmatically, i.e., tapping a partially obscured option scrolls it to the middle of the screen.


I did subclass the scroll view and confirmed it was receiving touches by overriding touchesShouldBegin. Any idea of a change in iOS 13 that might cause this behavior?


Answered by Vallette in 386354022

Turns out the issue isn't with the scroll view but with the segmented control. In iOS 13 you can swipe/pan to change the selected segment which prevents the scroll view from scrolling. The solution is to subclass the control, override

gestureRecognizerShouldBegin and paradoxically return true.


class NoSwipeSegmentedControl: UISegmentedControl {
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}


Here's a link to the relevant posting on stack overflow: https://stackoverflow.com/questions/58177165/ios-13-segmented-control-remove-swipe-gesture-to-select-segment

Sorry if I do not catch it.


Could you explain : The idea is that the user can scroll the segmented control back and forth.

What does scrollin a segmented control mean ? Do you mean it gets out of visible part ?


What was the effect (I mean which function called, such as viewDidAppear, …) before IOS13 that produced the desired effect ?

Thanks for the response. The scroll view's content is the control and the width of the control is wider then the device's screen. For instance the control has 8 segments but the screen is only wide enough to display 3 at a time. To see the other segments the user scrolls the view left or right. I can scroll the view progammatically but it doesn't scroll via user touches.


(I included a picture but it doesn't display)


You should detail the exact setup.

Unfortunately, no image possible on the forum.


Is it Swift or SwiftUI ?


have you defined constraints on different views ?

How is the scrollView defined (whole size, content offset …)


I tested some mockup code and seems to work (iOS 13 simulator).

I set the scrollView background to color to see it.


class ViewController: UIViewController {
   
    @IBOutlet weak var scrollView: UIScrollView!
   
    @IBOutlet weak var segmentedControl: UISegmentedControl!
   
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        scrollView.contentSize = CGSize(width: 1000, height: 1000)
        scrollView.contentOffset = CGPoint(x: 50, y: 50 )
    }

    @IBAction func selectSegment(_ sender: UISegmentedControl) {
       
        print(segmentedControl.selectedSegmentIndex)
    }
   
}


Then I can scroll the view and make next segments to appear.

I can select segments from 0 to 7.


Is is important that the scrollView contentSize be larger than the frame, otherwise, no scroll.

It's actually Objective-C - this code's been around for awhile - and as I pointed out this works fine for every version of iOS up to 13. Here's the relevent set-up code:

  NSInteger numSegs=typeControl.numberOfSegments-2;
  CGFloat offset=[self eventTypeScrollViewOffset];
  typeControl.frame=CGRectMake(0, 0, (kEventTypeScrollPadding*2)+(kEventTypeSegmentWidth*numSegs), typeScrollView.frame.size.height);
  typeScrollView.contentInset = UIEdgeInsetsMake(0, -offset, 0, offset);
  typeScrollView.scrollEnabled=YES;
  typeScrollView.contentSize=CGSizeMake(typeControl.frame.size.width-(offset*2),typeScrollView.frame.size.height);

and here's the output from the debugger after the scroll view has been set-up:

<UIScrollView: 0x7f93ba0d2600; frame = (0 0; 375 30); clipsToBounds = YES; autoresize = W+BM; gestureRecognizers = <NSArray: 0x600002f90360>; layer = <CALayer: 0x6000020fb880>; contentOffset: {188, 0}; contentSize: {1125, 30}; adjustedContentInset: {0, -187.5, 0, 187.5}>


As you can see the contentSize is set and larger then the frame.


Here's a link to screenshot that show's the actual implementation: https://i.stack.imgur.com/Fmpou.png

Accepted Answer

Turns out the issue isn't with the scroll view but with the segmented control. In iOS 13 you can swipe/pan to change the selected segment which prevents the scroll view from scrolling. The solution is to subclass the control, override

gestureRecognizerShouldBegin and paradoxically return true.


class NoSwipeSegmentedControl: UISegmentedControl {
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}


Here's a link to the relevant posting on stack overflow: https://stackoverflow.com/questions/58177165/ios-13-segmented-control-remove-swipe-gesture-to-select-segment

Thanks for feedback.


How do you swipe the segmented control ?


I can swipe the scollView, but nothing occurs when I swipe the segmented control.

As mentioned in the stack overflow posting in iOS 13 sliding your finger across a segmented control selects segments. I assume you're running 13 so I'm not sure why you're not seeing it.

iOS 13: UIScrollView no longer scrolls
 
 
Q