UIVisualEffectView blur constraint animation bug - ios

I'm having an issue expanding and contracting a UIEffectView. Its expands fine, but when it contracts it instantly snaps to its final height and slides into position, leaving behind a faint vibrancy effect in its wake. Heres a gif to illustrate the problem.
http://i.imgur.com/Lh8q7m1.gif
This happens in a new blank project setup as so:
Here is the animation code:
- (IBAction)toggleEffects:(id)sender {
[self.view setNeedsLayout];
if(self._effectsHeight.constant == 50){
self._effectsHeight.constant = 500;
}else{
self._effectsHeight.constant = 50;
}
[UIView animateWithDuration:1.5f
animations:^{
[self.view layoutIfNeeded];
}];
}

I think that you have to set the resizing code inside the animation block.Try this way:
[UIView animateWithDuration:1.5f
animations:^{
if(self._effectsHeight.constant == 50){
self._effectsHeight.constant = 500;
}else{
self._effectsHeight.constant = 50;
}
}];

Related

Constraints animation is incorrect

I created uiview custom class and implemented in Main View Controller
-(KPHomeChartCategory *)chartCategory {
if (!_chartCategory) {
_chartCategory = [[KPHomeChartCategory alloc] init];
_chartCategory.delegate = self;
_chartCategory.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_chartCategory];
[self.chartCategory.topAnchor constraintEqualToAnchor:self.topAnchor constant:-7.5].active = YES;
[self.chartCategory.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
self.chartCategoryLeftAnchor = [self.chartCategory.leftAnchor constraintEqualToAnchor:self.rightAnchor];
self.chartCategoryLeftAnchor.active = YES;
[self.chartCategory.heightAnchor constraintEqualToConstant:100].active = YES;
}
return _chartCategory;
}
I animated uiview custom class (KPHomeChartCategory) constraints in this way
-(void)openPanelTagAnimation {
self.chartCategoryLeftAnchor.active = NO;
self.chartCategoryLeftAnchor = [self.chartCategory.leftAnchor constraintEqualToAnchor:self.rightAnchor constant:-self.frame.size.width +105];
self.chartCategoryLeftAnchor.active = YES;
[UIView animateWithDuration:.6 delay:0 usingSpringWithDamping:1 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.customSwitch.alpha = 0;
[self layoutIfNeeded];
} completion:nil];
}
Now if you look at the video, you will notice that the first time I show customView, my collection view is shown from above but afterwards the animation seems to be perfectly straightforward ... can you make me understand why this thing?
Video Link
VIDEO ANIMATION
Why my animation first starts from top to bottom and only then is linear ? (the linear animation from right to left is the correct one and should be the first time the custom view is animated)
In the animation you posted the cells are animating because their initial size is CGSizeZero or some value close to that and then the collection view layout invalidates so their size is increased. You could avoid this by animating the transform property of your collection view. This will like solve the problem you mention here as well. For example in a simple demo, I can place a collection view by pinning top, left and right to its superview with a constant height. I set the cell sizes programmatically like:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(collectionView.bounds.size.width / 3.0, collectionView.bounds.size.height);
}
Then I use a CGAffineTransform to move the collection view off screen. For example:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.collectionView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, self.view.bounds.size.width, 0.0);
}
Finally, when I want to perform an animation, I set the transform back to its identity:
- (void)animate {
// Reversing and repeating for the sake of testing
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{
self.collectionView.transform = CGAffineTransformIdentity;
} completion:nil];
}
Using this method ensures that cells are always the same size and thus won't animate when constraints change in an animation block.
When I change constraints in my demo project this is the animation, notice the cell sizes change on the initial animation.
The same animation when setting transform:

UIView Animation using Frame only changes position and does not change size iOS

So the below code moves the self.nowGamePiece to the center of the board, but it doesn't not change the size to 500 x 500. In fact, no matter what those values (width and height in CGRectMake) are, size doesn't change in this animation.
Why? self.nowGamePiece should also change its size to 500x 500 too!
//self.nowGamePiece is a UIView
[UIView animateWithDuration:7 animations:^{
self.nowGamePiece.frame = CGRectMake(self.gameBoardImageView.center.x,self.gameBoardImageView.center.y, 500, 500);
//doing below only moves the self.nowGamePiece too. Size doesn't change
//self.nowGamePiece.frame = CGRectMake(100, 100, 500, 500);
} completion:^(BOOL finished){
return;
}];
I think this method may be bugged. I solved it using transform instead.
[UIView animateWithDuration:7 animations:^{
self.nowGamePiece.transform =CGAffineTransformMakeScale(7.0, 7.0);
self.nowGamePiece.center = CGPointMake(self.gameBoardImageView.center.x, self.gameBoardImageView.center.y);
} completion:^(BOOL finished){
return;
}];
Try setting the autoResizingMask property of your view. I suspect your image is a subview of your nowGamePiece view, and it's just not resizing the image when the frame of the superview gets changed.
self.nowGamePiece.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.nowGamePiece.autoresizesSubviews = YES;
Try this instead:
//self.nowGamePiece is a UIView
[UIView animateWithDuration:7 animations:^{
CGRect frame = self.nowGamePiece.frame;
frame = CGRectMake(self.gameBoardImageView.center.x, self.gameBoardImageView.center.y, 500, 500);
self.nowGamePiece.frame = frame;
} completion:^(BOOL finished){
return;
}];

xCode - UIVisualEffectView animating

I've an issue while animating a VisualEffetView.
Here is the code where I declare it.
UIBlurEffect* blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
effectView = [[UIVisualEffectView alloc] initWithEffect:blur];
effectView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
effectView.frame = self.bounds;
self.layer.borderWidth = 1;
[self addSubview:effectView];
When I animate the superview to make it grow, the Visual Effect follow the animation of the superview, but when I want to reduce it, the Visual Effect disappear instantly making the result very ugly ^^
Here is the code where I animate the superview (called recherche here)
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
CGRect f = recherche.frame;
f.size.height = 0;
[recherche setFrame:f];
}
completion:^(BOOL finished){
[recherche removeFromSuperview];
recherche = nil;
}];
Here is what I have when I make recherche disappear. The white square seems to be the Effect View because the color changes if I change the UIBlurEffectStyle. But blurring effect is missing x)
From above understanding, I figure out that you just need to reset height of effect view to achieve what you want.
Added code in animation block:
Check and let me know, is it full fill your expectation.
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
CGRect f = recherche.frame;
f.size.height = 0;
[recherche setFrame:f];
// Add this lines
CGRect effectViewFrame = effectView.frame;
effectView.size.height = 0;
effectView.frame = effectViewFrame;
}
completion:^(BOOL finished){
[recherche removeFromSuperview];
recherche = nil;
}];

Calling [table reloadData] removes table's position change from [uiview animatewithduration]

There is a button that horizontally shifts my table.
- (void)togglePreferencePageVisibility:(id)sender {
int translation = [self preferencesVisible] ? -PREFERENCE_TRANSLATION_HEIGHT : PREFERENCE_TRANSLATION_HEIGHT;
//animate tableview down
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
_table.center = CGPointMake(_table.center.x, _table.center.y+translation);
}
completion:^(BOOL finished){
}];
}
When I call [_table reloadData], the table reverts to its original position. I tried manually readjusting the table position, like so
NSLog(#"before %#", NSStringFromCGRect(_table.frame));
[_table reloadData];
_table.frame = CGRectMake(initialTablePosition.x, initialTablePosition.y+PREFERENCE_TRANSLATION_HEIGHT, _table.frame.size.width, _table.frame.size.height);
NSLog(#"after %#", NSStringFromCGRect(_table.frame));
but no luck. Also the frame's have the same y position before and after.
You need to also adjust the auto layout constraints using the NSLayoutConstraint class. You can add, remove or change the values of NSLayoutConstraints. This is a VERY common question on stack overflow right now, due to the change from iOS 7 to iOS 8.
If you do not adjust the layout constraints then the view will be repositioned back to its original location. reloadData redraws the UITableView which causes the view hierarchy to reexamine its positions e.t.c.
As an example of making a view with a width constraint narrower:
CGRect frame = myView.frame;
frame.size.width -= 100;
//Next line now needed in iOS 8
myWidthConstraint.constant -= 100;
[UIView animateWithDuration:0.5 animations:^{
[myView setFrame:frame];
}];
EDIT: moving back example:
CGRect frame = myView.frame;
frame.size.width += 100;
//Next line now needed in iOS 8
myWidthConstraint.constant += 100;
[UIView animateWithDuration:0.5 animations:^{
[myView setFrame:frame];
}];
When using auto layout, you should not set any frames. If you do, when the view needs to redraw itself, the frame will be reset to the frame defined by its constraints. You should add an IBOutlet to a constraint between your table view and the top (or bottom what ever works for your use) of its superview (I'll call it topCon in the example below).
- (void)togglePreferencePageVisibility:(id)sender {
int translation = [self preferencesVisible] ? -PREFERENCE_TRANSLATION_HEIGHT : PREFERENCE_TRANSLATION_HEIGHT;
//animate tableview down
self.topCon.constant += translation; // this might need to be "-=" depending on whether your constraint is to the top or bottom
[UIView animateWithDuration:0.3
delay:0
options: UIViewAnimationCurveEaseOut
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished){
}];
}

UIView animateWithDuration doesn't work with Rect width/height animation

The following code works. It animates all those components nicely
CGRect logoRect = self.logoImageView.frame;
CGRect loginBackgroundRect = self.loginControlsBkImageView.frame;
CGRect loginButtonRect = self.loginButton.frame;
CGRect tableViewRect = self.tableView.frame;
CGRect forgotPasswordRect = self.forgotButton.frame;
CGRect signupButtonRect = self.signUpButton.frame;
if (!iPhone) {
// ipad keyboard-on-screen re-layout
logoRect.origin.y-= 60;
loginBackgroundRect.origin.y-= 110;
loginButtonRect.origin.y-=110;
tableViewRect.origin.y-=110;
forgotPasswordRect.origin.y-=110;
signupButtonRect.origin.y-=200;
}
else {
// iphone keyboard-on-screen re-layout
if (portrait) {
logoRect.origin.y-=17;
logoRect.origin.x-=50;
loginBackgroundRect.origin.y-= 70;
loginButtonRect.origin.y-=70;
tableViewRect.origin.y-=70;
forgotPasswordRect.origin.y-=70;
//signupButtonRect.origin.y+=200; // get off screen!
} else {
logoRect.origin.y-= 30;
loginBackgroundRect.origin.y-= 25;
loginButtonRect.origin.y-=25;
tableViewRect.origin.y-=25;
}
}
[UIView animateWithDuration:0.2f
delay:0.0f
options:UIViewAnimationOptionCurveEaseIn
animations:^(void) {
self.logoImageView.frame = logoRect;
self.loginControlsBkImageView.frame = loginBackgroundRect;
self.loginButton.frame = loginButtonRect;
self.tableView.frame = tableViewRect;
self.forgotButton.frame = forgotPasswordRect;
self.signUpButton.frame = signupButtonRect;
}
completion:NULL];
Take the following code and add one line (see below) to animate the WIDTH of the logoImageView... and puff... only the logoImageView animation works - the rest simply doesn't move. as if the frame size animation causes everything else not to animate if in the same animation block.
if (portrait) {
logoRect.origin.y-=17;
logoRect.origin.x-=50;
loginBackgroundRect.origin.y-= 70;
loginButtonRect.origin.y-=70;
tableViewRect.origin.y-=70;
forgotPasswordRect.origin.y-=70;
//signupButtonRect.origin.y+=200; // get off screen!
} else {
logoRect.origin.y-= 30;
logoRect.size.width-= 30; // <------- LINE BEING ADDED HERE
loginBackgroundRect.origin.y-= 25;
loginButtonRect.origin.y-=25;
tableViewRect.origin.y-=25;
}
I'm at a loss here. Does anyone know what's going on?
Try to change whole frame, not just width. It should work.
Put these lines before commiting animation (not in block):
self.logoImageView.frame = logoRect;
etc.
And instead of using animate method try to use commit animations this way:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
// Here some more animation settings
// Here your animations
[UIView commitAnimations];

Resources