willMoveToSuperview is called twice - ios

I'm adding a view to my view controller. In this view I have implemented willMoveToSuperview. Now I experienced that this function is called twice:
When the view is added to the superview (as intended)
When the current view controller is dismissed (e.g. a new view controller is pushed on the stack of the navigation controller)
Is this the intended behavior? What other method could I use to detect if the current view is added to a superview only? didMoveToSuperview seems to do the same. Or should I use a variable which remembers how often the function is called?
Edit:
Now I think I found the reason why it is called twice. I'm using a hide method to dismiss the view. It's in C# but it shouldn't matter here:
UIView.Animate (
0.5, // duration
() => { Alpha = 0; },
() => { RemoveFromSuperview(); }
);
If I comment this out it isn't called twice. How can I keep the animation and assure that it is only called once?

When a view is added to a superview, the system sends willMoveToSuperview: to the view. The parameter is the new superview.
When a view is removed from a superview, the system sends willMoveToSuperview: to the view. The parameter is nil.
You can't prevent the system from sending willMoveToSuperview: when you remove the view from its superview, but you can check the parameter:
- (void)willMoveToSuperview:(UIView *)newSuperview {
if (newSuperview != nil) {
// not a removeFromSuperview situation
}
}

Related

Subview keeps moving when I push and pop navigation controller

image before pushing
This is what it's supposed to look like originally. The slider's added as a subview of the main view from Xib file on viewWillLoad, and I don't add it again if the subview exists on viewDidLoad. When I push, I call hidesBottomBarWhenPushed on the other view controller.
This is what I happens when I pop back:
image after popping
I have no idea why the subview does that.
Whatever you have set for bottom slider in viewDidLoad is the first time setting when view comes appear on screen. After that you have hide slider on push action, and goes to second view….right?
But when you come back to your view with pop, then how view can identify that it have show or hide that slider…? So, when you come back-I mean pop that time viewWillAppear is called. Put you code there…
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// whatever you want to do, this is just for suggestion
if (bottomSlider.hidden == TRUE) {
bottomSlider.hidden = FALSE;
}
else {
bottomSlider.hidden = TRUE;
}
}

How to rotate parent view when child view orientation changes

I'm having a problem adjusting a parent view's layout when orientation changes for it's child view. I have a collection view controller that, when one of the cells are tapped, pushes a child view on top. If an orientation change occurs while the child view is visible and it is dismissed, the parent view's collection view cells haven't adjusted for the new width.
I should note that this works fine if the parent view is visible.
The only thing that has fixed this for me is in the viewDidAppear method of the parent view controller invalidates the collection view layout, but for me it's too late as the user sees the animation of the collection view cells snap into place.
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView reloadData];
}
I would have preferred to use viewWillAppear, but that doesn't seem to do anything. It sounds like it can only adjust the cells when the parent view is visible.
Is there a way around this?
Referring to this answer, iOS does not send orientation change events to offscreen view controllers, making them an unreliable way to determine whether the view has been resized.
viewWillAppear: isn't working in your case because iOS doesn't resize the offscreen view controller's view until after it calls the method, so your invalidate and reload are being pulled off the wrong values.
I believe the iOS8+ viewWillTransitionToSize:withTransitionCoordinator: method fires even when offscreen, but I'm not positive. In my experience, the size it provides does not reflect the actual size of the view. What I personally like to hook into is viewWillLayoutSubviews, usually guarded with a width check:
#property (nonatomic) CGFloat lastWidth;
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
if (self.lastWidth != CGRectGetWidth(self.view.bounds)) {
self.lastWidth = CGRectGetWidth(self.view.bounds);
// Update your collection view here.
}
}
This way, whenever your view is going to resize (on display, inside an orientation change animation) you can update the size information.
try overriding -(void)viewWillLayoutSubviews: method in your parent view controller. In your case,it goes like this
-(void)viewWillLayoutSubviews {
[self.collectionView.collectionViewLayout invalidateLayout];[self.collectionView reloadData];
}
You could try invalidating your layout and reloading in the rotation handler methods.
For pre-iOS 8
willRotateToInterfaceOrientation:duration:
And for iOS 8+
viewWillTransitionToSize:withTransitionCoordinator:

UIView Animation Fails

So, I want to do some basic animations of labels and later views.
I have a label, I'm trying to get it to move when a view loads, so I call the following method at the end of viewDidLoad:
- (void)animateView {
NSLog(#"animateView");
[UIView animateWithDuration:20 animations:^{
// set new position of label which it will animate to
self.dcFirstRunDaysLabel.frame = CGRectMake(20,320,280,215);
}];
}
Instead of animating, the label appears in position.
I've tried every tutorial and read through the docs. I get no errors.
Any thoughts?
Cheers.
Try calling your animateView method in viewDidAppear. Because in viewDidLoad your view isn't visible yet.
viewDidLoad:
Called after the controller’s view is loaded into memory.
viewDidAppear:
Notifies the view controller that its view was added to a view hierarchy.

how to make a custom scroll container view controller?

There are two view controllers in my app, e.g, vc1 and vc2. The two view controllers are as the subviews of a scrollView, so the user can scroll the screen to switch the view. However, the simple implement has a problem: the viewWillAppear method of vc1 and vc2 is called only once. so I want to implement my scroll container view controller, which can call viewWillAppear method correctly, please tell me how to implement it.
I am not sure what you are trying to do, but I think a simple UITableView or UICollectionView may be better for you because they have datasource method that will automatically called when a view will show up in the screen. You can update your two views when you need to return a UITableViewCell or UICollectionViewCell.
I'm not sure if this will work, but I'm thinking you can check if the vc1 and vc2's frames are withing the screen's bounds in the delegate method of the scrollView.
I'm pretty sure there's a method being called every time the scrollView is being scrolled. In this method, you can check
//put this in your .h or something
BOOL vc1IsVisible = true;
//in the scrollView delegate-method that is called upon scrolling
if([self isInsideView:vc1])
{
if(!vc1IsVisible)
{
vc1IsVisible = true;
[vc1 viewDidAppear:NO]; //or whatever it is for animation
}
}
else
{
if(vc1IsVisible)
vc1IsVisible = false
//and viewDidDisappear?
}
and then create a method somewhere like this
-(BOOL)isInsideView:(UIViewController*)vc
{
//Check if vc.origin.y is greater than scrollView.size.height or something maybe?
//You can probably also try using the scrollView's contentOffset and use that
//relative to the viewController's sizes.
//if the viewControllers bounds are withing the scrolls bounds, return YES;
//else, return NO;
}
Sorry I can't really test anything just now. Maybe I'll make something and update the answer later if you haven't figured it out. And you need to do it with both. I'm sure you can figure out a better way to include both in one method with this, or even with one variable.
Since you are using ViewController by adding it subview of scrollview, by adding ViewController this way viewDidLoad, viewWillAppear, viewDidAppear will be called only once, I mean there is no use of viewWillAppear here as such, rather if you want to update anything in the added ViewController you should create a public class in ViewController and call it when you need an update..

Invalidate a timer that belongs to a UIView subclass

I have a repeating timer that belongs to a UIView subclass.
The class has a nib that loads it and I'm using ARC.
I'd like to invalidate the timer when the UIView is either...
Removed from its superview
The ViewController that contains its superView is popped off the stack.
I can't seem to find a method like viewDidDisappear on UIView.
Is there any other way to intercept this?
At the moment, after the ViewController is popped the timer keeps firing and creating NSLog outputs.
For the view controller being popped: just use viewDidDisappear or similar. There's also UINavigationControllerDelegate that may be useful.
For the view itself: have you tried using willMoveToSuperview: method in UIView? I haven't verified this, but in theory the view will move to superview nil when it is removed from its superview.
So try the following in your view:
- (void)willMoveToSuperview:(UIView *)superview {
if (!superview) {
// cancel timers
}
}
There's also a willRemoveSubview: method, but that would get called on the superview rather than the view being removed.
Have you tried invalidating it in the dealloc

Resources