How can I disable horizontal scrolling and page will change on click in paging using UIScrollView?
Asked Answered
P

3

13

I have a UIScrollView with pagingEnabled. Added 5 UIStackView to subview of UIScrollView and also had one UISegmentedControl. I want to show currently selected segment and also want to disable horizontal scrolling but the view will able to scroll vertically.

let take an example:

  • Let selected page index = 0
  • User not able to scroll or drag horizontally to navigate to next page.
  • The user can scroll vertically
  • Now User selected page index = 1 in UISegmentedControl
  • 2nd page will be visible
  • Now user not able to scroll or drag to 0 and 2 index

How can I achieve this functionality using UIScrollView

Tried logic:

- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];

CGFloat xOff = self.scrollView.frame.size.width * self.currentPage;
[self.scrollView setContentSize:CGSizeMake(xOff, self.scrollView.contentSize.height)];
//[self.scrollView setContentOffset:CGPointMake(xOff, 0) animated:true];

}

but using this UIScrollView after changing page When I scroll again go to 0 page.

Perihelion answered 1/8, 2018 at 9:52 Comment(8)
Calculate the Y positions of the selected page and set the contentOffSet of the scroll view to that position. As you have done in the commented line but here X will be always 0 just calculate Y properly.Risteau
but my problem is that how can I disable horizontal scrolling using my approach I am not able to disable it. Also X will not always 0 let width will be 355 and selected page is 1 so X will be 355?Perihelion
Can you please elaborate more I am not getting what are you trying to say? Please put an answer for better explanation. It will help me better.Perihelion
stackoverflow.com/users/2227743/moritz Why did you remove the Swift tag. I know both the language very well so I don't think it's a language specific question.Perihelion
The explained functionality can be implemented using UIPageViewController and UIViewController having UIScrollView as a subview. If you are implementation is not restricted to the UIScrollView only I can provide you solution.Kalong
@ShubhamDaramwar I have also think about UIPageViewController but when I go with this I need to perform so many changes in my existing project. Which is developed by someone else 2 years ago and I have some time limit.Perihelion
I wan some clarifications. 1)Is the content on the scrollView fixed? 2) Are you using autolayout?Kalong
Yes. It is in Autolayout. Content on the scroll-view is dynamic.Perihelion
R
8

You can use UICollectionView with paging enabled and inside you can implement UIScrollView with vertical scroll enable. Disable the UICollectionView scroll and change the index collection cell on click using below code:

accepted New, Edited Answer:

Add this in viewDidLayoutSubviews

SWIFT

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let indexPath = IndexPath(item: 12, section: 0)
    self.collectionView.scrollToItem(at: indexPath, at: [ .centeredHorizontally], animated: true)
}

Normally, .centerVertically is the case

Objective-C

-(void)viewDidLayoutSubviews {
   [super viewDidLayoutSubviews];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
   [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}
Riane answered 14/8, 2018 at 13:2 Comment(6)
please let me know if you are in any problem while implementing this.Riane
Thanks, Your code works fine. I am looking for more canonical answers.Perihelion
If it works fine it should be correct answer. what kind of more information you want.Riane
I am currently working on this solution. if it's running well I will mark it accepted soon. And also there is no need for .centeredVertically When applying it content scroll to center always. Remove it from your answer.Perihelion
Ok Cool. Let me know if you need anything.Riane
Did you able to implement?Riane
P
4

I am using this solution from my own question

In segmentDidChange() method

[self.scrollView.subviews makeObjectsPerformSelector: @selector(removeFromSuperview)];
self.scrollView.showsVerticalScrollIndicator = false;
self.scrollView.showsHorizontalScrollIndicator = false;

self.arrSubViews = [NSMutableArray array];

// Loading view's from xib's
// Now
UIView *containerView = [[UIView alloc]initWithFrame:self.scrollView.frame];
    containerView.translatesAutoresizingMaskIntoConstraints = false;

[self prepareStackViewforPage:index withContainerView:containerView];

Now preparing stackView for selected index

- (void)prepareStackViewforPage:(NSInteger)index withContainerView:(UIView *)containerView {

  [self.scrollView addSubview:containerView];

  [self applyConstraintsToParent:self.scrollView andSubView:containerView];


  UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:self.arrSubViews];
  [stackView setFrame:self.scrollView.frame];
  stackView.translatesAutoresizingMaskIntoConstraints = false;
  stackView.axis = UILayoutConstraintAxisVertical;
  stackView.spacing = 0;
  stackView.distribution = UIStackViewDistributionFill;
  stackView.alignment = UIStackViewAlignmentFill;
  [containerView addSubview:stackView];

  [self applyConstraintsToParent:containerView andSubView:stackView];

  [self.view updateConstraintsIfNeeded];
  [self.view layoutIfNeeded];
  [self.view layoutSubviews];
}

In applyConstraintsToParent:andSubView: method

- (void)applyConstraintsToParent:(UIView *)parentView andSubView:(UIView *)subView {
//constraints

NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
[parentView addConstraint:leading];

NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
[parentView addConstraint:trailing];

NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
[parentView addConstraint:top];

NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-8];
[parentView addConstraint:bottom];

NSLayoutConstraint *equalWidth = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0];
[parentView addConstraint:equalWidth];

leading.active = true;
trailing.active = true;
top.active = true;
bottom.active = true;
equalWidth.active = true;
}

Now it's just working fine but now I have following issues

  • View's added via xib height not changing dynamically

I have raised a question for this issue on UIStackView: Loading views from xib and updating height constraint of subView did not reflect any changes?

But this logic working fine in storyboard?

Storyboard Demo

Perihelion answered 8/8, 2018 at 7:1 Comment(0)
P
2

Following your question the answer in to set isScrollEnabled property of UIScrollView to false like following:

For Objective-C

[self.scrollView setScrollEnabled:NO];

For swift

self.scrollView.isScrollEnabled = false

As Apple documentation says about this property:

A Boolean value that determines whether scrolling is enabled.

If the value of this property is true , scrolling is enabled, and if it is false , scrolling is disabled. The default is true. When scrolling is disabled, the scroll view does not accept touch events; it forwards them up the responder chain.

So your scrollView won't accept touches, but content of your scrollView will.

And this doesn't disallow you to scroll your scrollView programmatically (which is changing contentOffset property of your scrollView). So when selected segment of your UISegmentedControl has changed you should calculate new content offset for your scrollView depending on pages size and set it, I advise you to use setContentOffset(_:animated:) method of UIScrollView to achieve scrolling.

Hope it helps.

Photoelectric answered 14/8, 2018 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.