UIScrollView - how to get rid of delay before scrolling? - iphone

I'm using a UIScrollView to display a custom UIView. When the user drags a finger across the UIScrollView, there is a noticeable delay before the display begins updating. If the user keeps touching the screen, the UIScrollView becomes very responsive after a short time. Subsequent attempts to scroll result in the same initial delay, followed by high responsiveness. This delay seriously affects the usability of the view and I would like to get rid of it.
In a test project I have written to try to get to the bottom of this issue, I have only been able to partially replicate the behaviour. The first time that the user scrolls is exactly the same - however any subsequent attempts to scroll are responsive straight away.
I have tried both setting delaysContentTouches = NO and subclassing UIScrollView so that touchesShouldBegin returns NO as suggested in multiple places online, but neither has worked.
I'm using MonoTouch on iOS 4.3, but Objective-C answers are fine. I would post code to help illustrate the issue, but since I have been unable to narrow down the problem this would be well over 1000 lines. Hopefully this is enough info to get a solution.
Does anyone know what might be causing this delay, and how I can get rid of it?

Some general suggestions for improving scrolling performance.
Have your scrolling views rasterize offscreen:
myView.layer.shouldRasterize = YES;
Set that property for each sub-view on the scrollview - do not set it for the children of those sub-views or you just eat up memory that way.
If your scrolling views do not need compositing, make sure you turn that blending off:
myView.opaque = YES;
Test using the simulator by leveraging these two features that appear on the Debug menu of the iOS Simulator:
Color Off-screen Rendered
Color Blended Layers
If that doesn't address your problem, and you have implemented UIScrollViewDelegate, double-check to make sure you are not doing anything time consuming in those methods - for example, based on your description, you might be doing something in scrollViewDidScroll, scrollViewWillBeginDragging, or scrollViewWillBeginZooming and if you are, optimize that so it happens before scrolling even begins. Also, make sure you're not doing anything in touchesBegan.

I suspect what is happening is there is some kind of interaction enabled in the content of your scroll view.
The system does not know if the initial touch down is going to be a tap on one of the subviews or a drag on the scroll view, therefore is causing a delay while it waits to see if you are going to lift your finger.
What are the subviews of the UIScroll view?
As an experiment set all the subviews of the UIScrollView to have userInteractionEnabled = NO, this will not be what you want, but its just a test. Is should scroll fine after this, otherwise I am wrong.

Related

iPhone: Best way to handle 400 UILabels in UIScrollview

I've been working on a crossword app for a while. The actual game runs in a UIScrollview, because the player should be able to scroll, zoom and pan.
To the UIScrollview i added a UITapGestureRecognizer that handles the touch-event, and calculates where the player touched. So far so good.
Afterwards I added about 400 UILabels to the UIScrollview. Each of them are "empty" until the player presses a button on the keyboard. My problem is that when i add these labels the whole UIScrollview become very slow and laggy in scrolling etc.
As the user guesses the right words green tiles will become visible. The tiles are loaded in as UIImageViews. This reduces the performance again.
I have looked at DTGridView, but I've got no luck with it.
Can you please help me out and try to guide me in the right direction?
i think you should implement the UIScrollview method drawRect you self instead of add 400 UILabel in it
you can set a NSArray contains 400 objects called "label";
when user pressed the button, you should calc the postion & test of the "label" &decide which "label" should display in the scrollview in current offset .
add 400 UILabels in one UIScrollview may cause the memory problem;
You need to use recycled label in your scrollview. That will improve the performance. To know how to reuse/recycle subviews in UIScrollView please check Apple WWDC videos on UIScrollView. WWDC 2010 Sample Code . Also check UIScrollView Class Refference UIScrollView Class Reference
You can get help from this link Creating Circular and Infinite UIScrollViews
I've been playing with this for the past while/days even. Using various related answers. But eventually I used instruments and a bit of commenting to see what was slow.
I remember someone saying layoutSubviews slows things when you addSubviews, so I took my "Local" code out of there. But nothing sped up.
So when using a breakpoint during my addSubview routine, I noticed the iOS system was actually in a superview's layout calls (navigationCtrlr) during viewDidLoad.
I introduced a 0.1 second delay before adding subviews and bam! I recommend dispatch_async to prevent crashes from race conditions, but that's another subject.
In short, it might be in LayoutSubviews even if you don't think you are there.

UIScrollView with embedded UIWebView not scrolling after holding

I have a UIWebView which is embedded in a UIScrollView. The webView is resized so that the scroll view manages all the scrolling (I need control over the scrolling).
In the webView I have disabled userSelection via '-webkit-user-select: none;'
Everything is working fine except one annoying detail. When I hold down my finger on the content before starting to scroll for about a second the scrollView won't scroll. My best guess is, that it has something to do with userSelection. The time is about the same it usually takes for the copy/paste/magnifying-thing to appear which usually disables scrolling as well.
I am running out of ideas on how to solve this. Every help would be greatly appreciated!
Thanks!
EDIT: Another aspect of the problem is, that the non-scrolling actually triggers JS-Eventhandler (click, mousedown, mouseup) inside my webView which leads to surprising app behavior. The user puts her finger down, waits, scrolls, nothing happens, removes her finger and this is perceived as a click, which feels wrong from a users perspective.
I would guess what is happening is that after that short duration, the scrollview is no longer interpreting the touch as being on it's view and instead passes the touch down to it's content views.
Have you tried delaying the content touches for the scrollview? This will essentially tell the scrollview to delay taking action on the touch event and instead to briefly monitor the touch and if the touch moves then it recognizes it as a swipe gesture for scrolling. If it doesn't move, it will eventually pass the touch along to it's subviews.
scrollView.delaysContentTouches = YES;
I think even then, there is a standard delay time before the scrollview will pass the touch events along the responder chain. If you hold for too long, it's going to naturally perceive it as being a press down event rather than a scroll event.
This question is not relevant anymore. As of iOS 5.0 the UIWebView is based on a real UIScrollView and also exposes that UIScrollView via a property. Use that instead.
And don't mess with UIWebViews embedded in UIScrollViews anymore. The documentation explicitly advises against that.
Relevant Documentation

Sidescrolling UI on iPhone

Please lead me in the right direction.
I need to provide user with small text centered on the iPhone screen. User can make quick scroll left or right in order to get the next or previous text. There can be hundreds of such text pieces. The process itself is similar to Photo application sidescrolling but much simple, no zoom.
As far as I can understand I need to use UIScrollView class, then call hundreds of addSubviews?
Is it the optimal way or I should always keep 3 subviews and replace them on the fly?
What kind of tricks should be used to achieve the "scroll and center" effect?
Thanks
You could use a UIScrollView with pagingEnabled = YES for the "scroll and center" effect, I guess.
Then only add the subviews that you're actually displaying, otherwise you'll run out of memory very quickly.
In the UIScrollViewDelegate, in -scrollViewDidScroll: you can get the current contentOffset and determine which subviews you need to add and which ones can be removed.

Making view transitions fast - do you use this hack?

I have an iPhone app that displays a modal view controller. The modal view controller shows two instances of a custom subclass of UITextView called RoundedTextView, an MKMapView, and a UIToolbar. I construct the viewController only once, and reset its data and present it each time the user summons it.
When showing this view controller with presentModalViewController, I noticed that the animation to show the view was choppy on the 3G. So, to speed it up, I set the alpha of the MKMapView and the two RoundedTextView objects to 0 on viewWillDisappear and back to 1 on viewDidAppear. This made it nice and fast. I also presume that I could remove the views from the superview to speed it up as well.
Does anyone else jump through these kind of hoops on the iPhone. Is there something else I should be doing to avoid this hack?
It's not a hack to simplify drawing during animation in order to make the animation more smooth. It is indeed a very valid technique.
You may be able to achieve similar performance improvements by setting all UI elements to Opaque, a technique also used to fix table view cell performance issues. You just have to make sure background colors match.
The main problem I had was I subclassed UIButton to make gradient buttons and I had the boundary mask enabled. This made the performance terrible. I removed that option and made my buttons square and it's blazin now.

UIPageControl render quirk with UIScrollView

I'm building an iPhone application and like most I am trying to implement a UIScrollView with a UIPageControl, however I am coming across a very quirky behavior, which I assume may be a bug. Hopefully one of you has seen this before because it is driving me nuts.
Basically, the page control works fine, everything is hooked up and works normally on all accounts EXCEPT, with certain placements of the UIPageControl within the UIView, the UIPageControl will cease to render.
I'll just take screenshots of the XIB window to help illustrate... here's a placement that works perfectly fine:
http://www.jasconi.us/prob1.png
The UIPageControl is placed physically above the UIScrollView. Works great, everything is visible and working.
The next two DO NOT work:
http://www.jasconi.us/prob2.png
http://www.jasconi.us/prob3.png
The first one is simply placed below the scroll view. Doesn't render at all.
The second one is placed above the scroll view without technically being inside of it. Also doesn't render.
What the hell is up with this? I've tried using
[[self view] bringSubviewToFront:pageControl];
...to no avail.
Any ideas?
OK I found the answer to this, it's a little six degrees of Kevin Bacon.
This isn't actually a software bug, but a XIB quirk, for some reason the lower placement of the page control in combination with the default settings for autosize and anchor seem to jettison the control into outer space.
If you turn off all auto-scaling and auto-sizing and auto-anchoring and all that other crap, the controls appear exactly as you expected. The fact that it appears reliably when placed above the ScrollView is an oddity.
shrug.
Hope this helps future iPhone initiates.
Did you check to make sure that numberOfPages is not 0?
If you set a breakpoint can you see that pageControl is not nil?
I was still encountering this exact same problem, even after trying everyone's posted answers. My issue ended up being a little more "DOH":
I was using UIPageControl at the bottom of a modal FormSheet, however, I forgot to set the size of the view as Form Sheet in the xib. This caused my page control to be off the screen and never visible.
Moral: set view size (Full, Form, Page, etc) in your xib on the base view.
This will sound like a real no brainer, but I got caught out by it.
By default, UIPageControl expects to be on a dark background. IE: The dots are light gray, and white for the current page.
I used UIPageControl on it's own with no scrollview to change the time range of a graph I was rendering with drawRect:
Long story short, the graph background was white, so the page controller worked, I just couldn't see it. The solution was putting the graph itself in a subview, and making the parent that contained the page control have a dark background.