I am developing an iPad app which presents to the user a set of zoomable pages. There is a (paged) UIScrollView used for scrolling between pages, and each page consists of another UIScrollView which allows pinch&zoom, and contains as subview the actual page content which is a custom UIView subclass with CALayer drawings.
Everything was working fine as of iOS 7.0.x. Unfortunately, when running the app on iPads updated to iOS 7.1, the pages'UIView is completely unresponsive to touch events: none of the UIGestureRecognizers attached to it is ever fired, touchesBegan/Moved/Ended methods are never called, and even pinch gestures that should be captured by the parent ScrollView are not recognized anymore if they happen inside the UIView's bounds (outside of it, they work).
When i set to NO the parent Scrollviews' scrollEnabled property, the touch events properly reach the UIView but of course this is not the behavior I need.
Apple documentation doesn't say anything about changes in UIKit framework, and I also have no clue on how to debug this, since on previous iOS releases everything was working as expected.
Any idea?
Edit 31/03/2014:
I was able to do some more debug, and noted that if I omit to add to the UIView's CALayer a couple of sublayers (that come from two custom subclasses of UIView), the problem doesn't occur.
I ended up solving my issue.
What I did was to stop adding the CALayers as sub-layers to the UIVIew, and instead adding the CALayers' parent views as sub-views to the main UIView.
I still have no idea on why this is happening in 7.1, given that no changes from 7.0 was mentioned in the documentation for this topic.
Anyhow, hope this can help...
Related
TL;DR
Is it a new feature in Xcode 14 and iOS 16 that a UIScrollView is now scrolled automatically when a view inside the ScrollView becomes firstReponder and the keyboard appears? While working on other iOS projects in earlier versions of Xcode and iOS I never came across this behaviour. Can this be controlled or deactivated?
Details:
While working with Xcode 14.0.1 on a new iOS project I noticed that an UIScrollView is now automatically scrolled when the content view becomes first responder.
Have a look at this example. I have created a new project, added a ScrollView to the ViewController and placed 12 subviews inside to fill it with some content. Subview no. 12 additionally holds a UITextField. The firstResponder status of this text field can be toggled using the top button.
When tapping on the button the TextField becomes firstResponder and the ScrollView is automatically scrolled up. However, not enough to make bring the TextField above the keyboard and make visible. Just enough to bring it above the bottom screen edge.
This does not make a lot of sense to me.
Is it possible to control this automatic scrolling or to deactivate it?
EDIT:
I have created CustomScrollView as UIScrollView subclass and did override scrollRectToVisible. When calling super.scrollRectToVisible everything works as before, but I could set a break point to see from where scrollRectToVisible is called.
The callstack shows the method scrollTextFieldToVisibleIfNecessary inside UITextField which uses delegateShouldScrollToVisibleWhenBecomingFirstResponder
However, UITextFileDelegate does not have such a method / value and scrollTextFieldToVisibleIfNecessary is also documented nowhere.
So, the question remains: How to disable this behaviour?
I have this strange issue. To start it all, this is how my view hierarchy
looks like:
I have a UIViewController with a UIScrollView with three separate ContainerView's inside it. Each of the ContainerView's frames (and respective UIViewControllers) are set programatically.
I open the second ContainerView with a UIView.animate(...) method. Inside this UIView/UIViewController I have a UITableView. The problem is that only the first five (and half of the sixth for some reason, but maybe that's a clue) UITableViewCell's are selectable. I have about five more UITableViewCell's which is for some reason not selectable.
I don't have any UITapGestureRecognizer's which has been the problem for some other people that I've seen. Also, if I add the TouchesBegan to either the UITableView or the UIViewController holding it, it behaves in the same manner. That will say, it only prints out when I touch the same part of the screen where the UITableViewCell's are selectable.
Is there anyone that have encountered the same issue or something similar to it that can shed some light over this?
Any help, input or thought is very much appreciated.
So I resolved this issue. For anyone else having similar problems this was because the underlying contentView of the UISrollView wasn't big enough.
Even though the UITableView, and even the views under it was visible, touches could not reach it since these are somehow registered through the UIScrollView contentView (for me, this was an UIView I added in the Interface Builder on top of the UIScrollView).
Also, if you are working with autoLayout, you have to change the contentViews constraints in the Interface Builder since UIScrollView.contentSize won't bother to listen to your commands.
I have a PageViewController which handles the gestures so I have not done anything with it. I disabled auto-layout in my storyboard so that I could use autoresize to fill the screen with views.
I have a tabbar and if I reload the page with the tabbaritem. The gesture are working.
How can I make the touch/gesture handler resize on orientation change?
http://kevindew.me/post/18579273258/where-to-progmatically-lay-out-views-in-ios-5-and
In the above link you will find usefull information about laying out and handling orientation changes. Also I had this problem once on a device with lower iOS version if your version can be updated you can try that however it's not a fix. I recommend to check the link and see if your views are properly layed out.
Think of a UIScrollView with embedded (subview) UIViews, arranged in a column. In iOS6 and previously, the scroll view could be configured so that when you flick it with your finger, the embedded views do not receive touch events even if the initial touch is on one of the subviews; but if you touch a subview without flicking, the scroll view decides this is not a scroll action and forwards the touch events to the embedded views. This was very convenient behavior if you wanted to be able to drag/drop the embedded UIViews within the UIScrollView.
In iOS 7 the documentation indicates that setting the UIScrollView property delaysContentTouches will cause touch-down events to be delayed until the UIScrollView decides whether it's being scrolled. But in fact, this simply does not appear to work. The subview immediately receives touch events and responds to them if the scrolling touch-down event is on one of the subviews. Thus if the subview is programmed for drag/drop it starts dragging while the scroll view also scrolls.
It appears that the model for this behavior has been changed, since iOS 5/6 both did suppress touch events while deciding whether this is a scroll action. Some new methods are now available to cancel the touch-down events after the UIScrollView decides it is scrolling. But obviously this is not useful if the drag/drop code has also started moving the subview.
My question: Is there any way to prevent iOS 7 UIScrollViews from invoking low-level touch-down events on its subviews, when you initiate a scrolling action by stroking a subview?
When I say "low-level", I mean actual touch events as opposed to using gesture recognizers. I am convinced that simply setting the delaysContentTouches property to YES does not work.
This problem has totally busted some quite complex code that worked smoothly and beautifully in iOS 5 and 6; and, so far I have discovered no way to tell the UIScrollView to suppress events to its subviews until it determines whether or not it is being scrolled. The events go through, then a cancellation touch event is triggered later, after the scroll view determines it is scrolling. It looks like the underlying model has been redefined for the worse, or this is a bug. Any insights will be greatly appreciated.
Are you sure it was working on iOS5/6? Based on my experience and posts like UIScrollview delaysContentTouches issue it doesn't work.
Maybe a sample code which shows it working on iOS5/6 but not on iOS7 will help to answer your question.
This works for me:
[scrollView setCanCancelContentTouches:YES];
[scrollView setDelaysContentTouches:YES];
I have a UIScrollView filled with subviews, all is well when creating it and initially filling it.
But when I add a new subview that is positionned outside of the visible screen portion, or when I just resize an existing subview that is also outside of the visible screen portion, there is a subsequent 0.3s-long scroll animation (I can see it happening from my delegate) that seems to match the newly added/resized element.
Attempts:
pagingEnabled is always NO.
Setting scrollEnabled to NO during subview manipulations doesn't help.
Doing a setContentOffset:animated:NO after subview manipulations doesn't prevent the animation.
One single giant subview with all my subviews in it doesn't help.
My current workaround is to initially set the frame to fit inside the visible screen portion, or doing resizing work inside another superview, but it feels dirty, and won't handle all situations...
Is there a way to prevent this automatic scrolling animation when programmatically manipulating subviews?
Xcode 4.3, iOS SDK for 5.1.
I too discovered this problem and found this solution http://www.iphonedevsdk.com/forum/iphone-sdk-development/94288-disabling-uiscrollview-autoscroll.html
It involves subclassing the UIScrollView and entering no code in the following method.
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated {
}
Like the guy says on the link I've found it works and no problems so far. Hope it works for you.
I had this problem because I set the content size of the scroll view prior to adding the subview.
As soon as I change the code so that the content size of the scroll view was set after adding the subview the problem went away.