UIView not animated properly using UIView Animation - ios

I am working on UIView Animation. I want to move a view upside while i scroll up and should move down when i scroll down.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint scrollVelocity = [_collectionViewLeaderboard.panGestureRecognizer velocityInView:_collectionViewLeaderboard.superview];
if (scrollVelocity.y > 0.0f){
NSLog(#"going down");
[UIView animateWithDuration:0.3f
animations:^ {
_headerview.frame = CGRectMake(0, 0, _headerview.frame.size.width, _headerview.frame.size.height);
_headerviewSecond.frame = CGRectMake(0, _headerview.frame.size.height, _headerviewSecond.frame.size.width, _headerviewSecond.frame.size.height);
self.collectionViewLeaderboard.frame = CGRectMake(self.view.frame.origin.x, _headerviewSecond.frame.size.height+_headerview.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
frameconditon = _headerview.frame;
_viewOptions.frame = CGRectMake(_viewOptions.frame.origin.x,_headerview.frame.size.height+_headerviewSecond.frame.size.height+30, _viewOptions.frame.size.width, _viewOptions.frame.size.height);
} completion:^ (BOOL completed) {
}];
}
else if (scrollVelocity.y < 0.0f){
NSLog(#"going up");
[UIView animateWithDuration:5.3 animations:^{
_headerview.frame = CGRectMake(_headerview.frame.origin.x, -(_headerview.frame.size.height), _headerview.frame.size.width, _headerview.frame.size.height);
_headerviewSecond.frame = CGRectMake(0, (_headerview.frame.size.height)-40, _headerviewSecond.frame.size.width, _headerviewSecond.frame.size.height);
self.collectionViewLeaderboard.frame = CGRectMake(self.view.frame.origin.x, _headerviewSecond.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
frameconditon = _headerviewSecond.frame;
_viewOptions.frame = CGRectMake(_viewOptions.frame.origin.x,_headerviewSecond.frame.size.height+20, _viewOptions.frame.size.width, _viewOptions.frame.size.height);
} completion:^(BOOL finished) {
}];
}
}

I believe its very simple thing if you want to move the view up and down.
Because If you add view in scroll view you can automatically get the view up and down along with the scroll. You just need to set "contentSize" property of scrollView.
If its not the case, you are trying to get panGesture of UICollectionView then you can not get in "scrollViewDidScroll" method.
Here is the useful tutorial on UIPanGestureRecognizer with UICollectionView. Hope so it will help.
https://uncorkedstudios.com/blog/using-uigesturerecognizers-with-uicollectionviews

Related

Animating custom UIView from off screen make its subviews not responding

I created a small custom UIView with a UILabel and a UIButton, this custom view is a banner to display at the top of the current view controller.
I load the view layout from a nib file and use a method from the custom view to display it with an animation, and the view will hide after a specific amount of time. Like this.
- (void)displayBannerInViewController:(UIViewController *)vc
{
CGFloat originY = 0;
if (vc.navigationController != nil) {
originY += 20 + vc.navigationController.navigationBar.bounds.size.height - self.bounds.size.height;
}
self.frame = CGRectMake(0,
originY,
[UIScreen mainScreen].bounds.size.width,
self.bounds.size.height);
if (vc.navigationController != nil) {
[vc.navigationController.view insertSubview:self atIndex:1];
} else {
[vc.view.window insertSubview:self atIndex:1];
}
[UIView animateWithDuration:0.3 animations:^{
self.frame = CGRectOffset(self.frame, 0, self.bounds.size.height);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 delay:self.duration options:0 animations:^{
self.frame = CGRectOffset(self.frame, 0, -self.bounds.size.height);
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}];
}
I set the action for the button inside the banner with this
[self.actionButton addTarget:self
action:#selector(executeActionBlock)
forControlEvents:UIControlEventTouchUpInside];
After animation showing the banner, and before is hidden, no matter how many times I tap on the button, the executeActionBlock method is never called.
I made a test setting the initial frame of the banner to origin (0, 0) and without animation and then the button worked fine. So, I don't know if a problem of the animation or because the original frame of the banner is in a non visible position. BTW, is important for the banner to not be visible because on the app is showing from under the navigation bar.
Thanks
You've written your code so that you run a series of animations, where the view is on-screen during the delay of the last animation. By default user interaction is disabled on views while they are being animated. Try passing UIViewAnimationOptionAllowUserInteraction in options for all your nested animations.
https://developer.apple.com/reference/uikit/uiviewanimationoptions/uiviewanimationoptionallowuserinteraction?language=objc
Well, it seems I should keep looking more because I found this question with the same problem. I tried the solution there and now is working.
The problem is that linking animations is not a good idea for user interaction so I used a NSTimer instead, like this.
- (void)displayBannerInViewController:(UIViewController *)vc
{
CGFloat originY = 0;
if (vc.navigationController != nil) {
originY += 20 + vc.navigationController.navigationBar.bounds.size.height - self.bounds.size.height;
}
self.frame = CGRectMake(0,
originY,
[UIScreen mainScreen].bounds.size.width,
self.bounds.size.height);
if (vc.navigationController != nil) {
[vc.navigationController.view insertSubview:self atIndex:1];
} else {
[vc.view.window insertSubview:self atIndex:1];
}
[UIView animateWithDuration:0.3 animations:^{
self.frame = CGRectOffset(self.frame, 0, self.bounds.size.height);
} completion:^(BOOL finished) {
[NSTimer scheduledTimerWithTimeInterval:self.duration target:self selector:#selector(hideBanner) userInfo:nil repeats:NO];
}];
}
- (void)hideBanner
{
[UIView animateWithDuration:0.3 animations:^{
self.frame = CGRectOffset(self.frame, 0, -self.bounds.size.height);
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}
And now works like a charm.

How to animate deletion of a label?

I have a view controller that have a scroll view that bounce horizontally , and in this scroll view I have a label.
I can now hold the label and scroll it down, and if I release it will bounce up back.
What I want is that: When I scroll the view y coordinate (using myScrollView.contentOffset.y) to some value, lets say -33 and under I can release my fine and the label will animate to the bottom of the screen and disappear, and now I can set the label to be a new value, and It will animate from top to the label original position.
Here a photo of how the view controller looks like:
And this is the relevant method I already implemented (powered by #rebello95):
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.myScrollView.contentOffset.y <= -73) {
[UIView animateWithDuration:0.3 animations:^{
self.homeLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.homeLabel removeFromSuperview];
self.homeLabel = nil;
}];
}
NSLog(#"%f", self.myScrollView.contentOffset.y);
}
Now I want it to slide to the bottom of the page and fade.
thanks!
EDIT: The animation now moves the label to the bottom of the view controller then fades it out.
You can use an animation block to move the label, then put another block inside the completion block to fade out the label, then remove it after the animation completes.
Example:
[UIView animateWithDuration:0.3 animations:^{
[self.myLabel setFrame:CGRectMake(self.myLabel.frame.origin.x, self.view.frame.size.height - self.myLabel.frame.size.height, self.myLabel.frame.size.width, self.myLabel.frame.size.height)];
self.labelRemoving = YES;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
self.myLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.myLabel removeFromSuperview];
self.myLabel = nil;
self.labelRemoving = NO;
}];
}];
Sidenote: You should probably be using <= instead of == in your if statement to achieve your desired results. In addition, you may want to set a flag to indicate that your label is being removed (since that method will inevitably be called multiple times). Something like this:
//.h
#property (nonatomic, assign) BOOL labelRemoving;
//.m
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.myScrollView.contentOffset.y <= -33 && !self.labelRemoving) {
[UIView animateWithDuration:0.3 animations:^{
[self.myLabel setFrame:CGRectMake(self.myLabel.frame.origin.x, self.view.frame.size.height - self.myLabel.frame.size.height, self.myLabel.frame.size.width, self.myLabel.frame.size.height)];
self.labelRemoving = YES;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
self.myLabel.alpha = 0.0;
} completion:^(BOOL finished) {
[self.myLabel removeFromSuperview];
self.myLabel = nil;
self.labelRemoving = NO;
}];
}];
}
NSLog(#"%f", self.myScrollView.contentOffset.y);
}

UISegementedControl reverts back to original frame after touch

Every time I click on my UISegementedControl it snaps back to its original frame. I can see it barely through my translucent toolbar.
I have a UIViewController with a UITableView, and UIToolBar like this:
There is a UISegmentedControl hidden just below the table view, behind the toolbar:
The Filter button calls the 'onFilterButtonPressed' method
- (IBAction)onFilterButtonPressed:(id)sender
{
if(self.filterBar.hidden){
[self showFilterBar];
} else {
[self hideFilterBar];
}
}
- (void)hideFilterBar
{
CGRect filterBarFrame = CGRectMake(0, self.view.frame.size.height+(self.filterBar.frame.size.height+1), self.filterBar.frame.size.width, self.filterBar.frame.size.height);
CGRect tableViewFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y,self.tableView.frame.size.width, self.tableView.frame.size.height+(self.filterBar.frame.size.height+1));
[UIView animateWithDuration:0.3 animations:^{
[self.filterBar setFrame:filterBarFrame];
[self.tableView setFrame:tableViewFrame];
} completion:^(BOOL finished) {
self.filterBar.hidden = YES;
}];
}
- (void)showFilterBar
{
CGRect filterBarFrame = CGRectMake(0, self.view.frame.size.height-(self.filterBar.frame.size.height+1), self.filterBar.frame.size.width, self.filterBar.frame.size.height);
CGRect tableViewFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y,self.tableView.frame.size.width, self.tableView.frame.size.height-(self.filterBar.frame.size.height+1));
self.filterBar.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
[self.tableView setFrame:tableViewFrame];
[self.filterBar setFrame:filterBarFrame];
}];
}
This is because of auto layout. With that turned on (which it is by default), you should do any positioning or resizing of views by modifying constraints, not setting frames.

Resize UIScrollView on Long Press Gesture

I have a UIScrollView at the very top (just below the navigation bar) of a UITableViewController using Storyboards. The UIScrollView's default size is 320x50. When the user holds the scrollView for at least 1 second, I want the UIScrollView to get twice as big (320x100) in order to show additional details with an animation. The UITableView right below it should animate with it if possible and move down 50.
Holding the UIScrollView for at least 1 second when it's in the bigger setting will result in the opposite animation, and the UIScrollView will animate back to its original size.
How would I do this? Thank you ahead of time! Here's what I have so far:
- (void)viewDidLoad {
[super viewDidLoad];
self.featureScrollExpanded = NO;
UILongPressGestureRecognizer* featureHold = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector (longHold:)];
[featureHold setDelaysTouchesBegan : YES];
featureHold.minimumPressDuration = 0.6;
featureHold.numberOfTouchesRequired = 1;
[self.featureScrollView addGestureRecognizer:featureHold];
[featureHold release];
}
- (void)longHold:(UIGestureRecognizer*)sender {
if (self.featureScrollExpanded==NO) {
self.featureScrollExpanded=YES;
//make it bigger
}
else {
self.featureScrollExpanded=NO;
//make it smaller
}
}
Do an animation:
CGRect frame = yourScrollView.frame;
frame.size.height += 50;
[UIView animateWithDuration:0.6
animations:^{
yourScrollView.frame = frame;
} completion:^(BOOL finished) {
//do your other animation here if you want to
//or do them both together and lose this block
}
];
Or if you want it a bit more with an overview:
CGRect frame = yourScrollView.frame;
frame.size.height += 50;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.6];
[self.yourScrollView setFrame:frame];
[UIView commitAnimations];

UIview animation overriding one view to another view

I'm new iphone developer i have problem uiview animation for ipad landscape mode.i have two view view1(like a split view) and view2(covered remaining window).when i touch move right to left view2 it will be overriding the view1 with moving animation.at same time when i touch move left to right view2 come and fit the old position.please share your ideas
With Regards,
Rajesh.
Hi all i found the answer finally,
- (void)viewDidLoad
{
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[recognizer setNumberOfTouchesRequired:1];
[secondView addGestureRecognizer:recognizer];
[recognizer release];
UISwipeGestureRecognizer *recognizerleft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwipeHandle:)];
[recognizerleft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[recognizerleft setNumberOfTouchesRequired:1];
[secondView addGestureRecognizer:recognizerleft];
[recognizerleft release];
[self.view addSubview:secondView];
[super viewDidLoad];
}
//To set the frame position of the view
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"rightSwipeHandle");
[UIView beginAnimations:#"viewanimations" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationDelegate:self];
secondView.frame=CGRectMake(360, 0, 660, 768);
[UIView commitAnimations];
}
//To set the frame position of the view
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"leftSwipeHandle");
[UIView beginAnimations:#"viewanimations" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationDelegate:self];
secondView.frame=CGRectMake(200, 0, 858, 768);
[UIView commitAnimations];
}
if i understand correctly, you want a sliding animation between 2 views. if so:
Make a ViewController that will hold these two views. inside this view controller's .m file define a transition method that contains the following and gets called by your buttons/other action triggers:
CGFloat windowWidth = self.mainView.frame.size.width;
CGFloat windowHeight = self.mainView.frame.size.height;
CGRect offScreenLeft = CGRectMake(-1*windowWidth, 0.0, windowWidth, windowHeight);
CGRect onScreen = self.mainView.frame;
CGRect offScreenRight = CGRectMake(windowWidth, 0.0, windowWidth, windowHeight);
if (direction == rightToLeft)
{
rightView.frame = offScreenRight;
[self.view addSubview:rightView];
[UIView animateWithDuration:0.65
animations:^{
leftView.frame = offScreenLeft;
rightView.frame = onScreen;
}
completion:^(BOOL finished){
[leftView removeFromSuperview];
}];
}else if (direction == leftToRight){
self.leftViewController.view.frame = offScreenLeft;
[UIView animateWithDuration:0.65
animations:^{
rightView.frame = offScreenRight;
leftView.frame = onScreen;
}
completion:^(BOOL finished){
[rightView removeFromSuperview];
}];
}
}
In general, make sure you are adding your subview to the view currently on screen, and make sure you set the appropriate bounds. Check that your view is not nil:
if(myView){
// not nil. thats good
}else {
// nil. this is bad. make sure myView is being initialized properly (if at all)
}
Finally, make sure neither the opacity nor the alpha property on your subview is set to 0 (you'll want these at 1 if you want it to show up completely and between 0 and 1 for a transparency effect).

Resources