ScrollsToTop feature is not working in iOS9 properly - ios

I have a UIViewController having a UITableView with large data. I want to implement the feature of scrolltotop on press of the statusbar.
I have a lot of UIView set through my storyboard so I first try to set scrollsToTop = NO for all and then set the scrollsToTop = YES for the UITableView specifically in viewDidLoad.
The same settings/configuration works with iOS8 but not with iOS9.
I have applied below code to disable scroll for all subviews in start:
- (void)disableScrollsToTopPropertyOnAllSubviewsOf:(UIView *)view {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)subview).scrollsToTop = NO;
}
[self disableScrollsToTopPropertyOnAllSubviewsOf:subview];
}
}

Try it using content offset
self.tableView.contentOffset = CGPointMake(0, 0 - self.tableView.contentInset.top);

Make sure you call it on viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Call scroll to top here
}
I hope this can help.

Fortunately, this started working flawlessly in iOS 10.0

You might have more than one UIScrollView in your view hierarchy, and you have to set only the one you want to scroll to top to Yes and the others scrollsToTop = No;.

Related

ios 8 - buttons in horizontal scroll view intercepting pan event - scroll does not work

I have a horizontal scroll view with a line of buttons. The scroll view will not scroll unless I do an extremely fast swipe.
If I set the buttons to userInteractionEnabled = NO, then the scrolling works as expected, but of course, then the buttons don't work at all.
This app worked fine in iOS 7 and before. It seems to be a iOS 8 "feature". I did notice that I can catch the button's drag event, but I don't know how to redirect it back to the scrollView.
I'm thinking I'll need to replace my buttons with UIViews and manage the events myself but I'd be grateful if someone has other ideas or solutions.
I found that in iOS 8, the UIScrollView's underlying UIPanGestureRecognizer is not respecting the UIScrollView's delaysContentTouches property. I consider this an iOS 8 bug. Here's my workaround:
theScrollView.panGestureRecognizer.delaysTouchesBegan = theScrollView.delaysContentTouches
I've had this problem with a UITableView which has custom UITableViewCells with UIButtons on it. I put this in my UITableview class.
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
return YES;
}
Solved my problem.
EDIT: Just to clearify, you can create a subclass of UIScrollview and add this to solve the problem.
This hack works for me:
UITapGestureRecognizer *nothingTap = [[UITapGestureRecognizer alloc] init];
nothingTap.delaysTouchesBegan = YES;
[_scrollView addGestureRecognizer:nothingTap];
credit: https://devforums.apple.com/thread/241467
I made a subclass of UIScrollView to fix this issue. You only need this method in it:
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
UITouch *touch = [touches anyObject];
if(touch.phase == UITouchPhaseMoved)
{
return NO;
}
else
{
return [super touchesShouldBegin:touches withEvent:event inContentView:view];
}
}
Then just remember to set the class to your subclass in the storyboard if you're using one and you're good to go.
I have same issue and I solved it by creating a subclass of UIScrollView and set it's cancelContentTouches value to TRUE and its working fine.
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
return YES;
}
Hope it will work for you.

UIView blocking UIScrollView's gesture recognizer

Hi I have a UIView on top of a UIScrollView like this. The UIView is a container that is itself transparent but has many subviews which are not.
-------------------------
- UIScrollView -
- -
- ------------- -
- - UIView - -
- ------------- -
-------------------------
The UIView is transparent but it prevents the UIScrollView from scrolling when touched. Some of the subviews are buttons so they have tap gestures that override the scrolling action but the transparent gaps in the frame of the UIView still blocks the scrolling gesture. Is there a way to prevent this from happening? I would still like to use it as a container to hold my other subviews.
You should not set userInteractionEnabled to NO hence you want it intractable. I think the right way is to subclass a UIView and override - pointInside: withEvent: like below.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint localPoint = [self convertPoint:point fromView:self];
for (UIView *subview in self.subviews) {
if ([subview pointInside:localPoint withEvent:event]) {
return YES;
}
}
return NO;
}
Use this view you can interact with subviews inside the view and scroll scroll view if not touch on subviews.
Thanks for the answers guys. But I found this solution which worked well for me:
How to get touches when parent view has userInteractionEnabled set to NO in iOS
Set userInteractionEnabled to FALSE on your view inside the scroll view.
myView.userInteractionEnabled = FALSE;

Swift UIScrollView not working with buttons [duplicate]

I have a horizontal scroll view with a line of buttons. The scroll view will not scroll unless I do an extremely fast swipe.
If I set the buttons to userInteractionEnabled = NO, then the scrolling works as expected, but of course, then the buttons don't work at all.
This app worked fine in iOS 7 and before. It seems to be a iOS 8 "feature". I did notice that I can catch the button's drag event, but I don't know how to redirect it back to the scrollView.
I'm thinking I'll need to replace my buttons with UIViews and manage the events myself but I'd be grateful if someone has other ideas or solutions.
I found that in iOS 8, the UIScrollView's underlying UIPanGestureRecognizer is not respecting the UIScrollView's delaysContentTouches property. I consider this an iOS 8 bug. Here's my workaround:
theScrollView.panGestureRecognizer.delaysTouchesBegan = theScrollView.delaysContentTouches
I've had this problem with a UITableView which has custom UITableViewCells with UIButtons on it. I put this in my UITableview class.
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
return YES;
}
Solved my problem.
EDIT: Just to clearify, you can create a subclass of UIScrollview and add this to solve the problem.
This hack works for me:
UITapGestureRecognizer *nothingTap = [[UITapGestureRecognizer alloc] init];
nothingTap.delaysTouchesBegan = YES;
[_scrollView addGestureRecognizer:nothingTap];
credit: https://devforums.apple.com/thread/241467
I made a subclass of UIScrollView to fix this issue. You only need this method in it:
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
UITouch *touch = [touches anyObject];
if(touch.phase == UITouchPhaseMoved)
{
return NO;
}
else
{
return [super touchesShouldBegin:touches withEvent:event inContentView:view];
}
}
Then just remember to set the class to your subclass in the storyboard if you're using one and you're good to go.
I have same issue and I solved it by creating a subclass of UIScrollView and set it's cancelContentTouches value to TRUE and its working fine.
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
return YES;
}
Hope it will work for you.

Scroll to top with status bar tap

I've looked through various SO questions on the topic and I have not found a solution. I have a UIViewController with a UITableView and a UICollectionView. I want the UICollectionView to scroll to the top, when the user taps it.
The documents say if you have more than one UiScrollView subclass - you need to set them to no and the UiScrollView you want to scroll to the top, to yes.
So I wrote this bit of code to go through all my views:
for (UIScrollView *view in self.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
view.scrollsToTop = NO;
}
}
self.collectionView.scrollsToTop = YES;
This way I am sure any subclass of UiScrollView has it's scrollsToTop property set to no.
However tapping on the status bar does not do anything.
Can someone tell me what I am missing here?
Thank you
It seems that you are only iterating through the subviews of your main view. Your UITableView may be nested inside another view. Try doing the following;
//in view did load
[self setScrollToTopFalse:self.view];
self.collectionView.scrollsToTop = YES;
-(void)setScrollToTopFalse:(UIView *)v
{
for (UIView * v1 in [v subviews]) {
if ([[v1 class]isSubclassOfClass:[UIScrollView class]]) {
((UIScrollView *)v1).scrollsToTop = NO;
}
[self setScrollToTopFalse:v1];
}
}

UIScrollView child jumping after UINavigationController push and pop

So I have a UIScrollView on my iPad app with a single child view (which itself is parent to all the controls). The scrolling all works fine on it. Rotating works fine (the whole view fits in portrait, scrolls on landscape). Once pushing a new screen on the UINavigationController, and then coming back breaks it.
It looks as if the frame of the scrollview's child has moved up, relative to the scroll position, but the scrollview has remained at the bottom (the entire child view has shifted upwards).
I've tried fighting the Constraints in storyboard, literally for hours, and cannot work out what could be causing this.
I had the same problem with scroll view and auto layouts (iOS 6 - doesn't work, iOS 7 - works fine), of course this is not perfect solution, but seems like it works. Hope it will help you:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self performSelector:#selector(content) withObject:nil afterDelay:0.0];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
offset = self.scrollView.contentOffset;
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.scrollView.contentOffset = CGPointZero;
}
- (void)content
{
[self.scrollView setContentOffset:offset animated:NO];
}
Get the frame of the subview before it disappears then manually reset the frame of the subview every time the view appears in -(void)viewWillAppear:(BOOL)animated.
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
globalFrameVariable = subview.frame;
[subview removeFromSuperview];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[subview setFrame:globalFrameVariable];
[scrollView addSubview:subview];
}
Here is a simple solution i found. (Assuming the parent view is meant to span the entire contentSize) Use this subclass of UIScrollView:
#interface BugFixScrollView : UIScrollView
#end
#implementation BugFixScrollView
-(void)layoutSubviews
{
[super layoutSubviews];
UIView *view=[self.subviews firstObject];
if(view)
{
CGRect rect=view.frame;
rect.origin=CGPointMake(0, 0);
view.frame=rect;
}
}
#end
It simply resets the origin every time auto-layout messes it up. this class can be used in InterfaceBuilder simply by changing the class name after placing the UIScrollView.

Resources