Manually calling UIRefreshControl and using setContentOffset - objective-c

I have implemented refreshControl as shown below in viewDidLoad():
refreshControl = [[UIRefreshControl alloc] init];
if (#available(iOS 10.0, *)) {
self.tableView.refreshControl = refreshControl;
} else {
[self.tableView addSubview:refreshControl];
}
Now I am presenting another viewController which has options to select filters. And after selecting those filters you come back again to current viewController having refreshControl.
I have added below code in viewDidAppear() for manually calling beginRefreshing:
if (self.filterChanged) {
self.filterChanged = NO;
[self.activityTableView setContentOffset:CGPointMake(0, - refreshControl.frame.size.height) animated:YES];
[refreshControl setHidden:NO];
[refreshControl beginRefreshing];
}
I have used setContentOffset for scrolling back to top and showing refreshControl.
The only problem is suppose my tableView is half scrolled in between then there is a big gap between refreshControl.
If my tableView is not scrolled then it works fine like I have pulled down to refresh, but if it is half scrolled then inspite of giving setContentOffset there is a big gap between refreshControl and tableview.

You need to wait for the scroll to finish before you can start the refresh. Unfortunately there is no completion block on setContentOffset, so try this.
After creating your refresh control set the target and create a corresponding method.
[_refreshControl addTarget:self action:#selector(refreshRequested) forControlEvents:UIControlEventValueChanged];
- (void)refreshRequested {
[_activityTableView reloadData];
}
In your viewDidAppear you scroll to top and refresh when done.
[UIView animateWithDuration:0.25 delay:0 options:0 animations:^(void){
self.activityTableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished){
[self.refreshControl beginRefreshing];
[self refreshRequested];
}];
When finished loading you need to end refresh and make sure to scroll back to zero position.
- (void)finishedLoading {
[_refreshControl endRefreshing];
[self.activityTableView setContentOffset:CGPointMake(0, 0) animated:YES];
}

Related

TvOS UITabBarController detect tabbar shown/hidden

Is there anyway to detect that the tabbar of a UITabBarController is going to appear or disappear? I want to make an animation simultaneously with the animation that shows/hides the tabbar.
I haven't find any way to detect this event. The property "hidden" of the tabbar is not an option because it changes its value once the animation has finished
The solution was to use the method in the view controller didUpdateFocusInContext:withAnimationCoordinator: with this code:
static NSString *kUITabBarButtonClassName = #"UITabBarButton";
NSString *prevFocusViewClassName = NSStringFromClass([context.previouslyFocusedView class]);
NSString *nextFocusedView = NSStringFromClass([context.nextFocusedView class]);
// The tabbar is going to disappear
if ([prevFocusViewClassName isEqualToString:kUITabBarButtonClassName] &&
![nextFocusedView isEqualToString:kUITabBarButtonClassName]) {
[self.view layoutIfNeeded];
self.constraintScrollViewCenterY.constant -= self.tabBarController.tabBar.frame.size.height;
[coordinator addCoordinatedAnimations:^{
[self.view layoutIfNeeded];
} completion:nil];
// The tabbar is going to appear
} else if (![prevFocusViewClassName isEqualToString:kUITabBarButtonClassName] &&
[nextFocusedView isEqualToString:kUITabBarButtonClassName]) {
[self.view layoutIfNeeded];
self.constraintScrollViewCenterY.constant += self.tabBarController.tabBar.frame.size.height;
[coordinator addCoordinatedAnimations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
where self.constraintScrollViewCenterY is a constraint related to the vertical alignment of the view I want to move according to the tabbar movement
Note: The use of class name (kUITabBarButtonClassName) instead of [... class] method is due to UITabBarButton is a private class

Strange controls animation after transitionWithView

I am trying to transition from one view to another.
The final view I'm transitioning to is a XIB with a couple buttons and a title bar.
My problem is that after the transition, the buttons get displayed on the very top left of the window for a fraction of a second, and eventually "drag" to their expected coordinates. Everything is perfectly usable and functional, but the transition looks a little funny.
Any idea what could cause this?
Here is my code snipet:
Homepage *hp = [[Homepage alloc] init];
hp.data = self.data;
[UIView transitionWithView:self.view duration:0.5
options:UIViewAnimationOptionTransitionCurlDown
animations:^ { [self.view addSubview:hp.view]; }
completion:nil];
[hp DisplayThumbnails];
[hp release];
I wanted to provide the code snippet that I've used to resolve this problem using Jacob's recommendation in case someone else runs into this. Here it is:
Homepage *hp = [[Homepage alloc] init];
hp.data = self.data;
[hp.view setHidden:YES];
[self.view addSubview:hp.view];
[UIView transitionWithView:self.view duration:0.5
options:UIViewAnimationOptionTransitionCurlDown
animations:^ { [hp.view setHidden:NO];}
completion:nil];
[hp DisplayThumbnails];

UIScrollView remove subview animated

What I have:
Basically I have collection of UIViews presented in horizontal scrollView. UIScrollView have paging enabled and each item is not full screen so I can see part of previous and next view based on this.
Each view have delete button on itself.
What I need:
I need to find good idea to animate reloading UIScrollView content after removing one of the subview. As I thought about it there will be 4 different kinds of deletion:
1. deletion of last view
2. deletion of first view
3. deletion of middle view - hardest one
4. deletion of only view - easiest one, just animation of view disappearing
I need some suggestions/solutions.
Thanks,
Michal
edit:
Ok, I havent implemented it fully.
Here is reload method:
- (void)loadScrollView{
for(UIView* view in [_scrollView subviews])
{
[view removeFromSuperview];
}
CGRect frame = self.scrollView.frame;
frame.origin.x = 0;
frame.origin.y = 0;
int i = 0;
_scrollView.clipsToBounds = NO;
_scrollView.pagingEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = NO;
for(MPContact* contact in self.items)
{
frame.origin.x = self.scrollView.frame.size.width*i;
MyView *view = [[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
[view setFrame:frame];
i++;
[view.nameAndSurnameLabel setText:#"view text"];
[view setDelegate:self];
[self.scrollView addSubview:view];[self.viewsArray addObject:view];
}[self.scrollView setContentSize:CGSizeMake(frame.size.width*[self.items count], frame.size.height)];}
Each MyView have delete button with delegate, delegate removes view from viewsArray and run this method for now.
I suggest you to use + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion method of UIView class. Just get your UIView that you want to delete, from UIScrollView and set view.alpha = 0 in animations block. In completion block remove this UIView from UIScrollView, using removeFromSuperView method. Setting alpha to 0 will make fade animation.
EDIT:
Iterate all your views you want to move and change it's x coordinate.
for(UIView *view in scrollview.subviews)
{
[UIView animateWithDuration:0.1 animations:^{
[view setFrame:CGRectMake(view.x-(/*HERE YOU NEED TO PUT WIDTH OF TOUR DELETING VIEW*/),view.y,view.width,view.heigh)];
}
completion:^(BOOL finished){
//remove view from superview and change your uiscrollview's content offset.
}];
}

Does presentViewController automatically destroy previous views?

I use a bunch of custom segues to segue from one view controller view to another using:
[self performSegueWithIdentifier:#"createTeamAccountSegue" sender:self];
My question is, do the previous views automatically get destroyed in iOS5 and 6?
I keep having to create custom segues to go to the next view, and then create yet another new segue animation in reverse to go back to the last view. As long as they dont keep stacking up and up then this should be fine right?
EDIT: I should probably show you the general layout of what my custom UIStoryboardSegue class looks like:
- (void) perform {
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
UIView *parent = sourceViewController.view.superview;
[parent addSubview:destinationViewController.view];
[parent sendSubviewToBack:destinationViewController.view];
sourceViewController.view.layer.masksToBounds = NO;
sourceViewController.view.layer.cornerRadius = 8; // if you like rounded corners
sourceViewController.view.layer.shadowOffset = CGSizeMake(0,0);
sourceViewController.view.layer.shadowRadius = 10;
sourceViewController.view.layer.shadowOpacity = 1;
destinationViewController.view.frame = CGRectMake(0, 20, destinationViewController.view.frame.size.width, destinationViewController.view.frame.size.height);
sourceViewController.view.frame = CGRectMake(0, 20, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
[UIView animateWithDuration:.3 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^
{
sourceViewController.view.frame = CGRectMake(0, parent.frame.size.height, sourceViewController.view.frame.size.width, sourceViewController.view.frame.size.height);
} completion:^(BOOL finished)
{
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL];
}];
}
If you are doing there segues in a UINavigationController then no, they aren't destroyed. To go back to one you should use [self.navigationController popViewControllerAnimated:YES];

animating a circle to grow

i am animating an UIImageView with an image of a circle that grows and fades which repeats:
-(void)animateOuterCircle
{
NSLog(#"animating circles");
[UIView animateWithDuration:1.5
delay:.5
options:(UIViewAnimationOptionAllowUserInteraction)
animations:^{
self.outerCircle.transform=CGAffineTransformMakeScale(.25, .25);
}
completion:nil];
[UIView animateWithDuration:1.5
delay:.5
options:(UIViewAnimationOptionRepeat | UIViewAnimationOptionAllowUserInteraction)
animations:^{
self.outerCircle.transform=CGAffineTransformMakeScale(1.5, 1.5);
self.outerCircle.alpha = 0;
}
completion:nil];
[self.view bringSubviewToFront:self.outerCircle];
}
i call this method in viewDidAppear:
- (void)viewDidAppear:(BOOL)animated
{
[self performSelectorOnMainThread:#selector(animateOuterCircle) withObject:nil waitUntilDone:NO];
//other code
}
It will animate fine when i load mainView. the issue is i load view2 and dismiss view2, when i come back to mainView, it is not animating anymore.
any ideas why this is happening?
EDIT: the methods are being called:
2012-03-15 14:11:13.946[1529:17903] view2 canceled //dismissing view2
2012-03-15 14:11:13.947[1529:17903] mapView viewWillAppear fired
2012-03-15 14:11:13.948[1529:17903] mapView viewWillAppear end
2012-03-15 14:11:14.352[1529:17903] mapView viewDidAppear fired
2012-03-15 14:11:14.353[1529:17903] animating circles
2012-03-15 14:11:14.354[1529:17903] mapView viewDidAppear end
EDIT 2:
-(IBAction) fourthBtn:(id)sender
{
view2 *view2 = [self.storyboard instantiateViewControllerWithIdentifier:#"view2"];
[self presentModalViewController:view2 animated:YES];
}
dismissing view 2:
-(IBAction) cancel:(id) sender
{
NSLog(#"heir canceled");
[self dismissModalViewControllerAnimated:YES];
}
also, i don't stop the animation myself at any point in my code.
My guess is that viewDidAppear is not being called, because from the perspective of that view, it never disappears.
Depending on how you are creating and displaying the view2, would this work within view2 when you close it?
[parentViewController viewDidAppear:YES];
i re-did some code;
-(void)viewWillDisappear:(BOOL)animated
{
[self.outerCircle removeFromSuperview];
[self.innerCircle removeFromSuperview];
}
- (void)viewDidAppear:(BOOL)animated
{
self.innerCircle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"inner-circle.png"]];
self.innerCircle.frame = CGRectMake(self.innerCircle.frame.origin.x, self.innerCircle.frame.origin.y, 30, 30);
self.outerCircle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"outer-circle.png"]];
self.outerCircle.frame = CGRectMake(self.outerCircle.frame.origin.x, self.outerCircle.frame.origin.y, 40, 40);
[self.view insertSubview:self.innerCircle belowSubview:HUD];
[self.view insertSubview:self.outerCircle belowSubview:HUD];
//other code
}
with these changes, it behaves as i want it too.
i think it had something to do with trying to animate the outerCircle a second time (it was already animating from first viewDidAppear, and when viewDidAppear was called a second time, it re-animated an already animating image and just borked it completely).