At the moment I'm creating some transitions and transform via CGAffineTransform
for a panning view and I'm running in troubles because of the transform performance under iOS 7
and an iPhone 4
.
I dived in Istruments and logged the stuff and the heavy lifting is done when I'm applying my transforms to the view.
Current Implementation
func handlePan(recognizer : UIPanGestureRecognizer) {
let drawerLocation = recognizer.locationInView(drawerView!)
let locationInView = recognizer.locationInView(containerView!)
let progressMax = containerView!.frame.height - 40 - 20
if(recognizer.state == .Changed) {
let offsetDrag = dragStartPosition.y - locationInView.y
let progress = Float(offsetDrag / progressMax)
if(offsetDrag >= 0) {
let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(normalizedProgress)))
viewWithTransform.transform = positionTransform // really bad performance here
} else {
// reset the transition
}
}
}
Workaround for iOS 7
func handlePan(recognizer : UIPanGestureRecognizer) {
let drawerLocation = recognizer.locationInView(drawerView!)
let locationInView = recognizer.locationInView(containerView!)
let progressMax = containerView!.frame.height - 40 - 20
if(recognizer.state == .Changed) {
let offsetDrag = dragStartPosition.y - locationInView.y
let progress = Float(offsetDrag / progressMax)
if(offsetDrag >= 0) {
if UIDevice.currentDevice().systemMajorVersion() > 7 {
let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress)))
viewWithTransform.transform = positionTransform // really bad performance here
} else {
viewWithTransform.frame = CGRectMake(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress)), drawerView!.frame.size.width, drawerView!.frame.size.height); // works like a charm on iOS 7
}
} else {
// reset the transition
}
}
}
Question
Why is the performance so bad on iOS 7 and my iPhone 4 with CGAffineTransforms
? Because it's doing the same thing with the offset then the frame setting in the workaround. When I use UIView.animateWithDuration()
with transform it's performing on 60fps. What can I do not to rewrite the whole implementation on my iOS 7 basis?
UPDATE 28th July Found out that AutoLayout is possible involved in this issue. Here is a TimeProfiler Stack from my current calls:
Now I'm facing a big problem in my current implementation, because I rely on AutoLayout. What's the easiest solution to solve this hassle on iOS 7?
While you are right that they do the same thing, under the hood, it is not that easy - there are matrix multiplications going all over the place. More on that can be found here.
It is strange that if you are doing just this, it affects your performance - but I guess your layout is complicated and so re-rendering takes a lot of time ; I actually had the same problem like a week ago, so here is what helped me:
Also, you can try to assign that transform in async call and see if that helps:
And if you really want to be fancy, use POP Framework from Facebook. It is great for what you want, and it allows you to do some fancy stuff like bounce, springiness etc. Here is how you can use it:
Edit: If you are just moving view around, use .center property, not the frame. It saves you need to define height / width again and gives clearer idea about your intentions.