I try to implement side bar menu. I already have done it with standard UIView
animations, but now i want to add some feelings to it. I decided to use UIViewDynamics
. I noticed that, after main view frame changed, it is necessary to recreate UIViewAnimator
and all behaviors.
I usually use layoutSubviews
view's method. But in that case, my controller inherit UINavigationController
and i couldn't override its view, so i worked with controller life cycle methods.
To avoid unexpected result, first i remove all animator behaviors in viewWillLayoutSubviews
method. After that, at end of viewDidLayoutSubviews
I create an animator and behaviors (gravity, item, push, collision).
That works fine, but when layoutSubviews
triggered, it is some lags (looks like low fps).
Some code:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
if (_animator) {
[_animator removeAllBehaviors];
_animator = nil;
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self configSubviewFrames];
[self configAnimator];
}
- (void)configSubviewFrames
{
CGFloat offset = [UIApplication sharedApplication].isStatusBarHidden ? 0 : _statusBarHeight;
CGRect drawerFrame, protectionFrame, unusedFrame;
CGRectDivide(self.view.frame, &drawerFrame, &unusedFrame, _drawerWidth, CGRectMinXEdge);
protectionFrame= self.view.frame;
if (!_isMenuShown) {
drawerFrame.origin.x -= _drawerWidth;
}
drawerFrame.origin.y += offset;
drawerFrame.size.height -= offset;
protectionFrame.origin.y += offset;
protectionFrame.size.height -= offset;
_drawerView.frame = drawerFrame;
_protectionView.frame = protectionFrame;
}
- (void)configAnimator
{
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
_collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_drawerView]];
_itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[_drawerView]];
_gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_drawerView]];
_pushBehavior = [[UIPushBehavior alloc] initWithItems:@[_drawerView] mode:UIPushBehaviorModeInstantaneous];
_itemBehavior.allowsRotation = NO;
_itemBehavior.elasticity = kDrawerElacity;
_gravityBehavior.gravityDirection = CGVectorMake(_isMenuShown ? 1.0f : -1.0f, 0.0f);
_pushBehavior.magnitude = 0.0f;
_pushBehavior.angle = 0.0f;
_collisionBehavior.collisionDelegate = self;
[_collisionBehavior setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(0, - _drawerWidth, 0, self.view.frame.size.width - _drawerWidth)];
[self addInititalBihaviors];
}
- (void)addInititalBihaviors
{
[_animator addBehavior:_collisionBehavior];
[_animator addBehavior:_pushBehavior];
[_animator addBehavior:_gravityBehavior];
[_animator addBehavior:_itemBehavior];
}
Hope you will help and feel free to ask any related questions. Thanks you.
App consume 9-12 % cpu on screen rotate.
P.S.: I already tried to move animator and behaviors creation into separated thread, but:
- Working with view in background thread - bad idea
- It just didn't help