unwind segue changed my UITableView bounds - ios

I have an unwind segue, but I don't know what unwind segue will do against the views' bounds. It indeed changed my UITableView bounds. Is there a way to re-size my views in/after unwind segue?
I find out that unwind segue will not call any view will/did appear nor load anything. I am confused why my UITableView bounds changed.
I created all view and controllers with storyboard. I got a sidebar and home view, and on sidebar, there is a setting button to load a setting view exactly the same size as the sidebar view.
When home view -> slide out sidebar, I manually calculated the table view bounds, in order to show all cells:
-(void) viewDidAppear {
[super viewDidAppear];
[self.ProjectTableView setFrame:CGRectMake(self.view.bounds.origin.x,
self.SideBarHeaderBGImageView.bounds.size.height + self.HomeButton.bounds.size.height + self.AlertButton.bounds.size.height,
self.view.bounds.size.width,
self.view.bounds.size.height - self.SideBarHeaderBGImageView.bounds.size.height - self.HomeButton.bounds.size.height - self.AlertButton.bounds.size.height)];
}
I use a unwind segue for the setting view to go back to side bar view:
- (IBAction)unwindToSideBar:(UIStoryboardSegue *)unwindSegue
{
// get the unwind view controllers
#ifdef DEBUG
NSLog(#"%# triggered unwind segue to SideBar", unwindSegue.sourceViewController);
#endif
if ([unwindSegue.sourceViewController isKindOfClass:[UserSettingViewController class]]) {
__block UIViewController *UserSettingVC = unwindSegue.sourceViewController;
//setup animateFrame
CGRect animateFrame = CGRectMake(-UserSettingVC.view.frame.size.width,
0,
UserSettingVC.view.frame.size.width,
UserSettingVC.view.frame.size.height);
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
UserSettingVC.view.frame = animateFrame;
UserSettingVC.view.alpha = 0.0f;
}
completion:^(BOOL finished) {
UserSettingVC.view.alpha = 0.0f;
[UserSettingVC willMoveToParentViewController:nil];
[UserSettingVC.view removeFromSuperview];
[UserSettingVC removeFromParentViewController];
UserSettingVC = nil;
//[self resizeSubViews];
//NSLog(#"self view height %f, bg %f, home %f, alert %f, proj y %f", self.view.bounds.size.height, self.SideBarHeaderBGImageView.bounds.size.height, self.HomeButton.bounds.size.height, self.AlertButton.bounds.size.height, self.SideBarHeaderBGImageView.bounds.size.height + self.HomeButton.bounds.size.height + self.AlertButton.bounds.size.height);
//NSLog(#"proj height %f", self.view.bounds.size.height - self.SideBarHeaderBGImageView.bounds.size.height - self.HomeButton.bounds.size.height - self.AlertButton.bounds.size.height);
}];
}
}
I tried to set the ProjectTableView frame again in the completion block, though it print correct values, but the real size is not correct.
I tried to print the UITable View bounds, seems normal, but my bottom cells cannot display. If I pull the window up, you can see them, but when release my fingers, it will go beneath the screen.
I suspect the unwind segue reset my UITable View size, but I don't know where to re-calcualate them again. The unwind segue will not invoke ViewDidAppear.

I figured it out, it is about auto layout. Disable or add enough layout will work.

Related

UIViewController changes dimension after modal presentation

I have a UIViewController which is presented using a custom transition, and by design it only fills 90% of the screen's height.
This appears fine, and I've never had any issues with it. Let's call it View A. Now I am trying to present a full screen modal view on top of this, let's call that View B. This appearance works, but when View B is dismissed, View A reappears, but has been expanded to fill the entire bounds of the screen.
Here's the presentation code I'm using:
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
...
// Presentation
const CGFloat viewHeight = (screenBounds.size.height * 0.9);
const CGRect beginFrame = CGRectMake(0, screenBounds.size.height, screenBounds.size.width, viewHeight);
const CGRect finalFrame = CGRectMake(0, (screenBounds.size.height - viewHeight), screenBounds.size.width, viewHeight);
// Dim
self.dimmedView.alpha = 0.0;
[transitionContext.containerView addSubview:self.dimmedView];
[transitionContext.containerView addConstraints:[NSLayoutConstraint allConstraintsFromViewToSuperview:self.dimmedView inset:UIOffsetZero]];
// Prepare
UIView * const toView = toVC.view;
toView.frame = beginFrame;
[transitionContext.containerView addSubview:toView];
// Animate
[UIView animateWithDuration:kAnimationDuration delay:0.0 usingSpringWithDamping:0.8 initialSpringVelocity:0.25 options:0 animations:^{
toView.frame = finalFrame;
self.dimmedView.alpha = 0.6;
self.tabBarController.view.layer.cornerRadius = 8.0;
self.tabBarController.view.transform = CGAffineTransformMakeScale(0.95, 0.95);
} completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
[offshootView removeFromSuperview];
}];
...
}
Has anyone seen this before, and know how to stop the system from resizing View A?
I think the problem is that you modify the size of the view controller's root view, although it is handled by the view controller. The documentation for UIViewController says:
A view controller’s root view is always sized to fit its assigned
space.
Why not add another (fully transparent) view as a child to the root view, where you place all your content? Doing so let's you keep the root view at 100% while changing the new view's size to 90% when you want to. If I understand you correctly this will accomplish the same thing without touching the root view.
For this to work you should set the view controllers Presentation property in the Storyboard attribute inspector to Over Full Screen. If you want to set it by code you set the view controller's .modalPresentationStyle = UIModalPresentationOverFullScreen. By setting this the underlying view controller will stay on screen after you have presented your view controller and continue to be visible where you have transparency in your view.
Documentation for UIViewController
Documentation for UIModalPresentationOverFullScreen

UISearchBar going to the view's top when I click on it

I have a UITableView which doesn't reach the entire view. Approximatively, the UITableView is two times smaller than the view.
Then, I add "Search Bar and Search Display Controller" to the UITableView from the Object library. So, to visualize, the searchBar appears at the screen's center.
Here's my view :
My problem : When I click into the search field to do my research, the searchBar is going to the top of the view, in place of the navigation bar ! And the transition is very awful... How can I constraint the searchBar to stay in its initial place ?
The problem is related to the search display controller. You don't have the control over the animation and it doesn't seem to handle it well when there's a view sitting on top of your TableView. We had the same exact problem and the easiest way we fixed it is by replacing the Search Display Controller by a simple Search Bar in the Storyboard.
That means your class will now have to implement the delegate method of the search bar to work properly.
To animate properly, simply override the searchBarTextDidBeginEditing and searchBarTextDidEndEditing like so:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.origin.y = tableViewFrame.origin.y - self.yourHeaderView.bounds.size.height;
[UIView animateWithDuration:0.25
animations:^{ self.tableView.frame = tableViewFrame; }];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.origin.y = tableViewFrame.origin.y + self.yourHeaderView.bounds.size.height;
[UIView animateWithDuration:0.25
animations:^{ self.tableView.frame = tableViewFrame; }];
}
Simply put, you just move the table view frame over the view based on it's height. The animation makes it smoother and cleaner.

Custom transition between UIViewControllers

I've just changed my app from being TabView driven to CollectionView driven, as there are too many sections of my app to be feasible for a TabView. When you start the app you are presented with several items in a CollectionView and selecting any of these items will take you to the relevant section of the app.
In XCode, the collection view lives in its own storyboard and each section of the app has its own storyboard.
In the CollectionView's didSelectItemAtIndexPath, I launch the relevant starboard as follows;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"relevant_storyboard" bundle:nil];
UIViewController* vc = [storyboard instantiateInitialViewController];
[self presentViewController:vc animated:YES completion:nil];
Now, none of the built-in transition animations really suit launching from a CollectionView, so I'd really like a custom effect, such as zoom in. However, I'm struggling to find any decent examples that work for me to create any kind of custom transition. I've tried [UIView transitionFromView], but I don't think that suits transitioning between UIViewControllers. I've tried transitionFromViewController:toViewController: but don't think I have the view hierarchy set up correctly. I've also tried using CATransition without success.
I've thought about doing it with a custom segue but, as my CollectionView is in it's own storyboard and have separate storyboards for each section of my app, I can't see how I can do this. At least not without having all sections of the app inside one storyboard, which would make the storyboard huge and difficult to manage.
So, can anyone give me any code examples or pointers on how I can solve this?
In my app I used a similar effect to zoom in from a thumbnail in a collection view cell to a child view controller that took up the entire screen. You could conceivably do the same thing for a navigation controller push as well.
In my code, I had a scoreView property on the cell subclass that I wanted to zoom up into the full screen. In your case, you may want to use a UIImageView with a screenshot of your new view. Alternatively, you could present the new view controller with a screenshot of the old view controller and then animate from there.
//Instantiate the view controller to be animated in...
//If the cell is not completely inside the collection view's frame, a dissolve animation might be more graceful.
BOOL dissolveAnimation = !CGRectContainsRect(CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height), cellRect);
//Get the frame of the cell in self.view coordinates, then the frame of the thumbnail view
CGRect cellRect = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
cellRect = CGRectOffset(cellRect, 0.0, -self.collectionView.contentOffset.y);
VSScoreCell *scoreCell = (VSScoreCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
CGRect scoreRect = dissolveAnimation ? CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height) : CGRectMake(cellRect.origin.x + scoreCell.scoreView.frame.origin.x, cellRect.origin.y + scoreCell.scoreView.frame.origin.y, scoreCell.scoreView.frame.size.width, scoreCell.scoreView.frame.size.height);
VSScoreView *scoreView = [[VSScoreView alloc] initWithFrame:scoreRect];
//Initialize the view that will be animated up (in this case scoreView)...
if (dissolveAnimation)
scoreView.alpha = 0.0;
[self.view addSubview:scoreView];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
if (dissolveAnimation)
scoreView.alpha = 1.0;
else
scoreView.frame = CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height);
} completion:^(BOOL finished) {
if (finished)
{
//Add scoreDisplayController as a child view controller or present it without animation
[scoreView removeFromSuperview];
}
}];
Of course, the new iOS might make this easier (my lips are sealed), but I hope this is somewhat helpful for your situation!
Have you tried the UIView animation block?
[UIView animationWithDuration:1.0 animation^ {
// do custom animation with the view
}completion:^(BOOL finished) {
if(finished) {
NSLog(#"Finished");
}
}];
It allows you to do custom animations when dealing with UIView(s), and even with UIViewControllers. I use it alot when dealing with custom animation actions.
EDIT:
for example, if you'd like to make the view of the current controller to move up the screen, and the second view controller to slide down in place of it, just do
[UIView animationWithDuration:1.0 animation^ {
// do custom animation with the view
// make sure CoreGraphics.framework is imported
// sliding current view to the top of the screen
self.view.transform = CGAffineTransformMakeTranslation(0,0);
// sliding 2nd view down..
// uncomment the following line, and one of the options for translation
//SecondView *sv = [[SecondView alloc] init];
// just edit the x,y in CGAffineTransformMakeTranslation to set where it will go
//sv.view.transform = CGAffineTransformMakeTranslation(320, 480) // iphone 4
//sv.view.transform = CGAffineTransformMakeTranslation(768, 1024) // ipad 1
}completion:^(BOOL finished) {
if(finished) {
NSLog(#"Finished");
}
}];
Hope this helps!

How to do "pushviewcontroller" animation WITHOUT using pushviewcontroller?

I want to do animation like NavigationController pushviewcontroller's animation.
but I don't have a NavigationController, I don't want to make it.
So I want to ask is it possible to do it's animation in UIViewController? thanks!
oh forgot to say, I'm trying to switch view after clicking button.
Using presentModalViewController now, but I don't like it's animation..
You could animate the origin property of your sub view, make it decreasing along the x axis just after adding it to the main view.
EDIT :
Use something like this :
// retrieve the screen bounds
CGRect sBounds = [[UIScreen mainScreen] bounds];
// the origin point is just on the right of the screen
CGRect newFrame = CGRectMake(sBounds.size.width,
0.0,
sBounds.size.width,
sBounds.size.height);
// set your view frame
[mySecondView setFrame:newFrame];
// add it to the main view
[mainView addSubview:mySecondView];
// then animate your view
[UIView animateWithDuration:0.5 // set the interval you want
animations:^{
mySecondView.frame.origin = sBounds.origin;
}
];
I would use a navigation controller and hide the navigation bar, but as you don't want to do that you can switch between views using [UIView beginAnimantion: #"myAnimation" withContext: nil]; and changing the frame or the origin.

Animated Subviews

I have a split view controller in my Ipad app, in which the detail view has subviews which are UITableView's.
The functionality I am trying to implement is to get an info view at the same position of a subview when a button(info button) on the subview is pressed. I need to get this info view by animation and that animation is that when the info button is pressed, that subview alone would flip (UIAnimationOptionFlipFromRight) and the info view would show...
This is how try to implement it -
-(void) showInfoView: (id)sender
{
infoView = [[InfoViewController alloc] initWithNibName:#"ViewViewController" bundle:nil];
infoView.view.frame = CGRectMake(250, 300, 200, 200);
[UIView transitionWithView:self.view duration:1
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[self.view addSubview:infoView.view];
}
completion:nil];
}
When I run the simulator and press the info button on any subview, what happens is that the animation happens perfectly, i.e. the subview flips from the right but the infoView is not getting displayed.
It would be great if someone could tell me where I am going wrong here.
The basic steps of performing an animation to onscreen is as follows:
Create the view.
Move it to the initial (offscreen) position
Add to the view hierarchy
Perform the animation.
It seems like you're skipping step 3 and possibly step 2.
Did you try setting the subview frame to the frame of your superview, i.e
info.View.frame = self.view.frame;

Resources