Making view transitions fast - do you use this hack? - iphone

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.

Related

UIScrollView stopping my UIGesture from doing view transition

So I am working on this project here, to test some things that I am interested about, such as view transitions using UIGestures.
I am currently testing how view transitions behave when they have things like UIWebViews and UIScrollViews in them. What I have found out currently is that if you have a UIScrollView bigger than the view frame then the transition (using gestures) is blocked if you are using a UIGesture to change the view. (Such as swipe left or right)
I was wondering if there is a way around this or a solution that I don't know about..
Try using
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
return no for it and see if that works.

UIScrollView - how to get rid of delay before scrolling?

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.

Recreate UIPickerView with just one row showing

I need a "PickerView", that behaves like a normal UIPickerView, but only shows one row of data and has a custom design.
Something like you see in the image, showing the transition from subview 1 to subview 2. After the user lifts his finger and after the scrolling stops, only one subview will be shown:
IMAGE
So basically a scrollview which:
is endless in both, positive and negative directions by showing the same entries over and over
uses paging across several subviews
only shows one subview when not scrolling, and no more than two subviews when scrolling.
I can get a endless scrollview to work, but not with paging enabled. Paging will always limit my scrolling to the next subview.
So I'm thinking about creating my own UIView subclass which custom scrolling behaviour to mimic a UIPickerView. But before doing so, I wanted to get some opinions about the idea in general. Is creating a custom UIView the right way to go? Anyone has some experience with the expected performace? (There will be timers to handle the scrolling algorithm, which has to be recreated of course... :)
Another approach would be to subclass UIScrolView and implement the paging myself. I know when the scrollView starts decelerating
, so maybe there is a way to overwrite the contentOffset to have it scroll into the right position...?!
Any help is appreciated! Thanks!
Here is a great custom component, which seems to be able to do everything you need:
http://dev.doukasd.com/2011/04/infinite-scrolling-dial-control-for-ios/
It's not endless, but rather a modified UITableView with a huge number of cells.
Would it be feasible to just use a UIPickerView, but clipped to the middle row? You could turn off showsSelectionIndicator to remove the overlay and have the delegate pass back custom row views.

Show a UINavigationBar back button without pushing a view controller

In the iPad's Photos app, when you tap an album the stack of pictures expands to fill the screen - you're in the same view, it's just rearranged the grid a little. But at the top, a left-arrow-style Back button appears, as if pushViewController had been used - except it fades in neatly, rather than sliding in. When you tap that, it fades out again, rather than sliding out.
Is there a way to replicate this behaviour? I've tried a few options so far, and might just be missing something. What I've tried:
Setting self.navigationItem's leftBarButtonItem works, but gives me a square button rather than an angled Back-style one - there are a few hacks online to make this work, such as using pictures for the button, but I'd rather only use them if there's definitely no "official" way to do this.
Setting self.navigationItem.backBarButtonItem - this is generally used to customise the back button when a view controller is pushed, so it has no effect.
[self.navigationController.navigationBar setItems::] - this works, although it gives me the sliding animation rather than fading. As a result, I use animated:NO to make it just appear. Downside: when tapping Back, you do get the sliding out animation, which looks weird because the rest of the UI stays still.
Has anyone managed to replicate this effect?
Thanks in advance!
Your first approach is probably the best.
It doesn't have to be super-hacky, you can use a normal UIButton and customize it to look like a back-button using backgroundImageForState: and titleForState: (etc.), then set the UIButton object as the customView of your UIBarButtonItem.
Many apps these days customize the look & feel of the buttons anyway, so using a custom background image is quite normal. If you use resizableImageWithCapInsets: (or stretchableImageWithLeftCapWidth:topCapHeight: if you need to support iOS earlier than 5.0) then the button can still stretch to fit whatever text goes inside, and as it's a normal UIButton the text is localizable, etc. I don't consider this approach to be hacky, it is a perfectly sensible way to get around the limited functionality of UIBarButtonItem objects.
Better late than never.
To show a back button without pushing a view controller, use pushNavigationItem:animated: and popNavigationItemAnimated: on UINavigationBar. These result in the standard slide animation and creation of a back button. However, there is no way to ensure your content animation runs for the same time as the bar animation other than making an educated guess at the duration.
Since iOSĀ 7 there is a better API for achieving this effect, where you still push and pop view controllers but you provide a custom transition animation through navigationController:animationControllerForOperation:fromViewController:toViewController: from UINavigationControllerDelegate. This allows the animations between the bar and content to be perfectly coordinated.
Finally, if your content before and after is managed by UICollectionViewController, you can use useLayoutToLayoutNavigationTransitions, which is designed for use-cases like Photos.

iPhone SDK view scrolling not rubber banding or using momentum from swipes

I'm having a fundamental problem with getting scrolling to work normally on my iPhone app. I have two views, each created in IB (although I've tried this programmatically and it makes no difference) which scroll very sloppily. Instead of the scrolling that we're used to (which is smooth and continues to scroll and eventually dampen and rubber band at the top/bottom), my scrolling only scrolls as long as my finger is in contact with the view. Swiping down quickly on a view has no more effect than swiping slowly. And when you scroll beyond the top or bottom, the view just stays there scrolled with empty area above/below.
One of my views is a UITableView and the other is a UIScrollView. Both have exactly the same problem and are in different XIBs, coupled to different classes, so this is why I think I'm missing a key concept in general.
My UITableView is a child to a UIView (since there is also a nav bar at the top) with my UIViewController's view connected to the UIView. The referencing outlets datasource and delegate are both hooked to the UITableView. Nothing is subclassed here aside from the ViewController of course which has overrides to populate the table.
In the second instance, I again have a non-subclassed UIView which my UIViewController's view is connected to. I have a subclassed UIScrollView as a child to the UIView and then a have a subclassed UIView (with larger size than the scroll view) as a child to the subclassed UIScrollView. This in itself seems ridiculously complicated to me, but I was not able to get scrolling working at all with fewer than 3 views (again there is a nav bar at the top of the non-subclassed UI-View). I am overriding drawRect: in my UIScrollView, which is putting the content up fine except for this scrolling issue.
Is there something I'm doing wrong organizationally? I've come across many suggestions on stackoverflow and other sites for UIScrollView and none make a difference. And I don't see anyone having scrolling issues with UITableView. I'm not pasting in any code because I would have to post full classes at this point (making the post ridiculously long) and I believe the problems to really lie with the way I'm using IB.
Thanks!!
OK, it turns out that this has nothing to do with UIKit. This code is part of a game I'm developing using cocos2d and that framework is what is causing the problem. For those who are developing on cocos2d, you cannot use FastDirector and expect scrolling to work in UIViews. Just remove any code like [[Director sharedDirector] useFastDirector] and everything will be fine.
Some code might help narrow down your problem.
In the mean time, try creating a new project in Xcode using the 'Navigation-based Application' template and take a look at how the navigation controller is being created in MainWindow.xib. Take a look at how the UITableViewController subclass called 'RootViewController' is defined and how the corresponding xib is setup too. You'll notice there is no UIScrollView explicitly defined anywhere but you get scrolling functionality from the tableview controller 'for free'.
This should give you a pretty good starting point down the right path. I question the need for overriding drawRect: without seeing some code or fully understanding your goal.
Take a look at:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
http://developer.apple.com/iPhone/library/featuredarticles/ViewControllerPGforiPhoneOS/UsingNavigationControllers/UsingNavigationControllers.html