Animated UIPickerView not rotating in landscape mode - iphone

I have a UIPickerView that animates up and down in a UITableViewController. I adapted an example from apple (DateCell). The UIPickerView is created programmatically, no nib files.
In Portrait mode everything looks nice. When I rotate the simulator (I not testing on the device), the UITableView rotates well, but the picker remains were it was. I read tons of threads about that topic and many developers seem to have problems with pickers behaving weird in landscape mode but at least their pickers rotate. I made a subclass of UIPickerView as described in this link: http://www.llamagraphics.com/developer/using-uidatepicker-landscape-mode, but it didn't help for the rotation issue.
I tried to rotate the picker with a transform but it looked very weird, like broken.
I'm suspecting that the problem is that I'm using the picker inside of a UITableViewController, and so I add it as a subview of self.view.window. If I try to add the picker as a subview of self.view, only a white frame (without any picker) appears.
Any suggestions?
The initialization code in the UITableViewController subclass:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.pickerView.superview == nil)
{
//Initialization code
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect initFrame = orientation == UIInterfaceOrientationPortrait ? CGRectMake(0, 0, 320, 200) : CGRectMake(0, 0, 480, 160);
self.pickerView = [[RotatingUIPickerView alloc] initWithFrame:initFrame];
[self.pickerView setDelegate:self];
[self.pickerView setShowsSelectionIndicator:YES];
[self.pickerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
[self.view.window addSubview:self.pickerView];
// compute the start frame
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGSize pickerSize = [self.pickerView sizeThatFits:CGSizeZero];
CGRect startRect = CGRectMake(0.0,
screenRect.origin.y + screenRect.size.height,
pickerSize.width, pickerSize.height);
[self.pickerView setFrame:startRect];
// compute the end frame
CGRect pickerRect = CGRectMake(0.0,
screenRect.origin.y + screenRect.size.height - pickerSize.height,
pickerSize.width,
pickerSize.height);
// start the slide up animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
// we need to perform some post operations after the animation is complete
[UIView setAnimationDelegate:self];
[self.pickerView setFrame:pickerRect];
[UIView commitAnimations];
}
}
Implementation of UIPicker subclass as described on the link above:
- (id)initWithFrame:(CGRect)frame
{
if (self == [super initWithFrame:frame])
{
for (UIView * subview in self.subviews)
{
[subview setFrame:self.bounds];
}
}
return self;
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
if (self == [super initWithCoder: aDecoder])
{
for (UIView * subview in self.subviews)
{
[subview setFrame:self.bounds];
}
}
return self;
}

By executing:
[self.view.window addSubview:self.pickerView];
you are adding pickerView as a subview of your UIWindow. I don't know how the main UIWindow can be rotated, if it can be.
When you are adding pickerView to the view
[self.view addSubview:self.pickerView];
you get problems due to the view being a UITableView.
What I suggest is adding pickerView to some intermediate UIView, added as subview to UIWindow and to which you add the UITableView. This intermediate UIView would also have a UIViewController associated to it so that shouldAutorotateToInterfaceOrientation can return the proper value to have auto rotation working.

Related

Cannot change UIView frame size

I have a custom uiview that i am trying to update the frame size. I do it like this in a method once it is clicked. The method is called, and the frame value changes, however on the screen nothing happens!
if (!touched) {
GameBox *box = (GameBox *)[self.view viewWithTag:40];
[box setFrame:CGRectMake(20, 20, 100, 73)];
NSLog(#"%f", box.frame.origin.x);
markButton.enabled = NO;
guessButton.enabled = NO;
[self.view reloadInputViews];
NSLog(#"The action bar should now be hidden");
}
else if (touched) {
guessButton.enabled = YES;
markButton.enabled = YES;
[self.view reloadInputViews];
NSLog(#"The action bar should now be visible");
}
I guess you have hooked self.view to UIView in Interface Builder.
In order to change UIView frame, in Interface Builder go to File Inspector, and uncheck Use Autolayout, then in the code change the frame.
Hope this helps.
You need to set adjust the frame in the viewDidAppear (not viewDidLoad).
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
CGRect frame = self.tableView.frame;
frame.origin.y += 100.0;
frame.size.height -= 100.0;
self.tableView.frame = frame;
}
Apparently this has something to do with table views within navigation controllers.
It is because of Auto Layout, however you could do it after Auto Layout done its work or change constraints of it. If you want to do it after auto layout add following.
- (void)viewDidAppear:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
box.frame = CGRectMake(20, 20, 100, 73)];
});
[self.view reloadInputViews] is generally used for FirstResponders. I Don't have much of an idea about your customview, but I think for just settings the frame you can use:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
viewFrame.frame=frame;//Frame Defined by you
[UIView commitAnimations];
can give better solution if i get a look at your custom view.

presentModalViewController in CGRect

Is it possible to present a modal view controller in such a way that the modal view is confined to the space included in a CGRect?
If not, please explain how to replicate the cross-disolve modal view transition between two views.
Thanks.
To cross-dissolve to a regular view controller, you can set it's modalTransitionStyle to UIModalTransitionStyleCrossDissolve then present it modally.
To perform a cross-dissolve between some pair of subviews (confined to their frame CGRects), you can use this UIView method:
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion.
Here's how you might use that in code:
#interface ViewController ()
#property(strong,nonatomic) UIView *redView;
#property(strong,nonatomic) UIView *blueView;
#end
#implementation ViewController
#synthesize redView=_redView;
#synthesize blueView=_blueView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.redView = [[UIView alloc] initWithFrame:CGRectMake(40.0, 40.0, 240.0, 100.0)];
self.redView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.redView];
self.blueView = [[UIView alloc] initWithFrame:CGRectMake(40.0, 40.0, 240.0, 100.0)];
self.blueView.backgroundColor = [UIColor blueColor];
}
- (IBAction)crossDisolve:(id)sender {
UIView *fromView = (self.redView.superview)? self.redView : self.blueView;
UIView *toView = (fromView==self.redView)? self.blueView : self.redView;
[UIView transitionFromView:fromView
toView:toView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {NSLog(#"done!");}
];
// now the fromView has been removed from the hierarchy and the toView has been added
// please note that this code depends on ARC to release objects correctly
}
The harder part of your question is the idea of making that new sub-view "modal" by which I'm guessing you mean that covers only part of the display but takes input focus exclusively. The nearest thing to that in the SDK is UIAlertView.
How about you just use UIView animations:
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(x,y,w,h)];
[view setAlpha:0];
[self.view addSubView:view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[view setAlpha:1];
[UIView commitAnimations];
Voila! It fades in! :)

Why does the keyboard not show in my UITextView?

I have a container class which is a view controller.
It holds the UITextView for notes and has another view controller as a subview, called it PDFViewController. That one has an array of view controllers, called them PageViewController's, in it and a UIScrollView so i can swipe through the different view controllers from the array.
Each of the PageViewController's has also an UIScrollView, so i can zoom the different pages.
But when I show my UITextView i cannot edit or write anything.
It shows a blinking cursor, but no keyboard and can't write text.
When i highlight a word from the default text, it shows me some dictionary options but the words won't be replaced.
I just don't know where the problem might be.
container.m (View Controller)
- (void) initNotes {
notesVisible = FALSE;
notes = [[UITextView alloc]initWithFrame:CGRectMake(10, 10, note_width, note_height)];
notes.backgroundColor = [UIColor yellowColor];
notes.font = [UIFont fontWithName:#"Arial" size:24];
notes.text = #"Hier ist Platz für Ihre Notizen";
container = [[UIView alloc] initWithFrame:CGRectMake(start_x, start_y, container_width, container_height)];
container.backgroundColor = [UIColor yellowColor];
[container.layer setShadowColor:[[UIColor blackColor] CGColor]];
[container.layer setShadowOffset:CGSizeMake(2.0, 3.0)];
[container.layer setShadowOpacity:0.6];
[container.layer setShadowRadius:5];
container.layer.shouldRasterize = YES;
[container addSubview:notes];
[self.view addSubview:container];
}
- (void) showTextView {
[UIView beginAnimations:#"MoveAndStrech" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
container.frame = CGRectMake(start_x, self.view.center.y-container_height, container_width, container_height);
[UIView commitAnimations];
notesVisible = !notesVisible;
}
- (void) hideTextView {
[UIView beginAnimations:#"MoveAndStrech" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
container.frame = CGRectMake(start_x, start_y, container_width, container_height);
// [notes resignFirstResponder];
[UIView commitAnimations];
notesVisible = !notesVisible;
}
#implementation PDFViewController
- (void)awakeFromNib
{
painting = false;
dataInstance = [PDFDataInstance sharedInstance];
chapter = [dataInstance chapter];
[self getNumberOfPages];
kNumberOfPages = dataInstance.pages;
// Register observer to be called when a cell from BookmarkPDFController is pressed
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didSelectBookmark:)
name:#"bookmarkPressedinPDFView" object:nil];
// Register observer to be called when a cell from BookmarkPDFController is pressed
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(togglePainting:)
name:#"togglePainting" object:nil];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++)
{
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.delegate = self;
scrollView.directionalLockEnabled = YES;
currentPage = [[chapter currentPage] integerValue];
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
//
// Load pages based on currentPage cause of when coming from bookmarks
[self loadScrollViewWithPage:currentPage];
[self loadScrollViewWithPage:currentPage+1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
}
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= kNumberOfPages)
return;
// replace the placeholder if necessary
PageViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{
//page+1 cause CGPDF indexing starts with 1
controller = [[PageViewController alloc] initWithPageNumberAndUrl:page+1: [chapter urlOnFilesystem]];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (controller.view.superview == nil)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
TextView delegates
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"begin editing");
}
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText
{
NSLog(#"something changed");
return YES;
}
Just want to add another possibility here. In the iOS simulator, make sure the "Hardware/Keyboard/Connect Hardware Keyboard" is not checked. It took me a couple of hours to figure out this. I guess I toggled that option by accidently pressing the shortcut. Not good experience :(
As pictured, Connect Hardware Keyboard should be UN-checked.
Is the UITextView receiving touches? Implement the UITextViewDelegate methods and see if they get called (esp textViewDidBeginEditing: and textView: shouldChangeTextInRange: replacementText:). This way you'll know for sure whether the text view is indeed handling the touches or not.
If it does, then I don't see anything wrong with your code (except you might have accidentally added a view overlapping the textview)
No one asked , but have you set :
notes.editable = YES ;
?
Make sure that in the delegate of your textview. Following method is returning YES.
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return YES;
}
After you have set the notes delegates, do the following.
- (void)textViewDidBeginEditing:(UITextView *)textView {
if ([textView isEqual:notes]) {
NSLog(#"notes begin editing");
}
}
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText {
if ([aTextView isEqual:notes]) {
NSLog(#"something changed in notes");
}
return YES;
}
This should confirm delegates of notes are indeed getting called.
you need to implement your container class with UITextViewDelegate
and add notes.delegate=self; just after initialize the notes object in initNotes method.
Check for 2 things:
Is notes.editable = YES; if so please change it to NO.
2.Check whether your UITextView delegates are called are not. If not Please make sure you include in your implementation file and set notes.delegate = self.
Try without container, just use the UITextView (notes) as the container itself.
Every time you used container use notes instead.
And then dont:
[container addSubview:notes];
[self.view addSubview:container];
Just:
[self.view addSubview:notes];
Tell me how it goes
I had similar behavior, the UITextView not responding to touches and the keyboard not showing.
My UITextView was layered on top of a UICollectionView which was receiving all the touches even though the UITextView was visibly on top.
I fixed it by adjusting the frame of the UICollectionView so that the UITextView has nothing behind it. After that, all the delegate methods were called like a charm.
Hope this helps.
please Refer this one. where ContantView is your view/textfield and _bubbletable is your table.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.2f animations:^{
CGRect frame = _ContantView.frame;
frame.origin.y -= kbSize.height;
_ContantView.frame = frame;
frame = _bubbleTable.frame;
frame.size.height -= kbSize.height;
_bubbleTable.frame = frame;
}];
}

Iphone: Is it possible to hide the TabBar? (Pre-iOS 8)

I have an application that uses a UITabBarController to switch between modes. When in a certain mode, I'd like to hide the tab bar until the steps of that mode have been completed. Note that I'm not using a navigation controller so I can't use the setHidesBottomBarWhenPushed method on the navigation controller to hide the tab bar.
Prior to iOS 8, When I attempt to hide the tarbar using:
self.tabBarController.tabBar.hidden = YES
the tab bar goes away, but it leaves a 50 pixel blank area at the bottom of the screen where the tab bar used to be. I can't seem to figure out how to fill that area. Anything in the UI that is in that area is clipped and cannot be seen.
Any ideas if this is even possible? I'd really like to stay away from the navigation controller.
Here's my code for that:
This is, of course, mucking with the goings on in the controller's view hierarchy. It could change/break. This uses defined APIs, so Apple won't care, but they won't care about breaking your code, either.
- (void)hideTabBar {
UITabBar *tabBar = self.tabBarController.tabBar;
UIView *parent = tabBar.superview; // UILayoutContainerView
UIView *content = [parent.subviews objectAtIndex:0]; // UITransitionView
UIView *window = parent.superview;
[UIView animateWithDuration:0.5
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds);
tabBar.frame = tabFrame;
content.frame = window.bounds;
}];
// 1
}
- (void)showTabBar {
UITabBar *tabBar = self.tabBarController.tabBar;
UIView *parent = tabBar.superview; // UILayoutContainerView
UIView *content = [parent.subviews objectAtIndex:0]; // UITransitionView
UIView *window = parent.superview;
[UIView animateWithDuration:0.5
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds) - CGRectGetHeight(tabBar.frame);
tabBar.frame = tabFrame;
CGRect contentFrame = content.frame;
contentFrame.size.height -= tabFrame.size.height;
}];
// 2
}
Edit:
An anonymous user has suggested the following addition for 7.0 (i have not tested this, and could not say whether it is a workaround or an ideal implementation):
// 1. To Hide the black line in IOS7 only, this extra bit is required
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
[self.tabBarController.tabBar setTranslucent:YES];
}
// 2. For IOS 7 only
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
[self.tabBarController.tabBar setTranslucent:NO];
}
Edit: Entirely untested in 8.x and likely lacking in some layouts.
Like Steve, I haven't found a clean way to do this (even though Apple Photopicker does something similar). Here is what I have done:
if (systemAction)
{
// Reveal tab bar back
CGRect bounds = [[UIScreen mainScreen] bounds];
CGRect tabBarFrame = self.tabBarController.tabBar.frame;
self.tabBarController.view.frame = CGRectMake(0,0,bounds.size.width,bounds.size.height);
self.toolBar.hidden = YES;
systemAction = NO;
}
else
{
//hide tab bar
CGRect bounds = [[UIScreen mainScreen] bounds];
CGRect tabBarFrame = self.tabBarController.tabBar.frame;
CGRect navigationBarFrame = self.navigationController.navigationBar.frame;
self.tabBarController.view.frame = CGRectMake(0,0,bounds.size.width,bounds.size.height+tabBarFrame.size.height);
self.toolBar.hidden = NO;
CGRect frame = self.toolBar.frame;
frame.origin.y = bounds.size.height - frame.size.height - navigationBarFrame.size.height;
self.toolBar.frame = frame;
systemAction = YES;
}
What it is doing is pushing the view down so I can display a toolbar (and not hiding it). Obviously this is for only the 'root view' of a tabbar + navigation controller. For any subsequent views you can set the 'hidesBottomBarWhenPushed' on the viewcontroller you are pushing.
I tried a number of the solutions above, but no joy in iOS 8. I find that setting in viewWillAppear the following works for me. Should work in iOS 7 as the extendedLayoutIncludesOpaqueBars was introduced then.
self.extendedLayoutIncludesOpaqueBars = true
self.tabBarController?.tabBar.isHidden = true
self.tabBarController?.tabBar.isOpaque = true
and if you need to turn tabBars on again when you leave to use the following in viewWillDisappear.
self.tabBarController?.tabBar.isHidden = false
self.tabBarController?.tabBar.isOpaque = false
I use this to allow a return from a transition to keep the TabBar hidden. Not used it in a button action but if like me you find nothing above now works, this could be the basis of a programmable solution.
It's a bit late in the day, but of all the answers to the question that I've trawled through this afternoon, this is the one that worked best for me.
How to hide uitabbarcontroller
// Method call
[self hideTabBar:self.tabBarController];
// Method implementations
- (void)hideTabBar:(UITabBarController *) tabbarcontroller
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
for(UIView *view in tabbarcontroller.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, 480, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 480)];
}
}
[UIView commitAnimations];
}
- (void)showTabBar:(UITabBarController *) tabbarcontroller
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
for(UIView *view in tabbarcontroller.view.subviews)
{
NSLog(#"%#", view);
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, 431, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 431)];
}
}
[UIView commitAnimations];
}
I use only this single line to achieve this. I use prepareForSegue method before showing the view controller having the tab bar.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showLogin"]){
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
}
I had worked on almost the same case, actually used the code from http://www.developers-life.com/hide-uitabbarcontrolleruitabbar-with-animation.html and made it better according to my needs, this might help others too.
I am using a UISplitViewController as the root view controller and its detail portion is a UITabBarController, I had to hide the tabbar in portrait mode:
// In UITabBarController's custom implementation add following method,
// this method is all that will do the trick, just call this method
// whenever tabbar needs to be hidden/shown
- (void) hidetabbar:(NSNumber*)isHidden {
UITabBarController *tabBarController=self;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGRect tabbarFrame=CGRectZero;
for(UIView *theView in tabBarController.view.subviews) {
//NSLog(#"%#", view);
if([theView isKindOfClass:[UITabBar class]]) {
tabbarFrame=theView.frame;
if ([isHidden boolValue]) {
tabbarFrame=CGRectMake(tabbarFrame.origin.x,
tabBarController.view.frame.size.height,
tabbarFrame.size.width,
tabbarFrame.size.height);
} else {
tabbarFrame=CGRectMake(tabbarFrame.origin.x,
tabBarController.view.frame.size.height - tabbarFrame.size.height,
tabbarFrame.size.width,
tabbarFrame.size.height);
}
theView.frame=tabbarFrame;
break;
}
}
for(UIView *theView in tabBarController.view.subviews) {
if(![theView isKindOfClass:[UITabBar class]]) {
CGRect theViewFrame=theView.frame;
if ([isHidden boolValue]) {
theViewFrame=CGRectMake(theViewFrame.origin.x,
theViewFrame.origin.y,
theViewFrame.size.width,
theViewFrame.size.height + tabbarFrame.size.height);
} else {
theViewFrame=CGRectMake(theViewFrame.origin.x,
theViewFrame.origin.y,
theViewFrame.size.width,
theViewFrame.size.height - tabbarFrame.size.height);
}
theView.frame=theViewFrame;
}
}
[UIView commitAnimations];
}
I used following code to call the hidetabbar: method
//In my UISplitViewController's custom implementation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
#synchronized(self){
//change the self.splitDetailController to your UITabBarController's object
[self.splitDetailController
performSelector:#selector(hidetabbar:)
withObject:[NSNumber numberWithBool:UIInterfaceOrientationIsLandscape(interfaceOrientation)]
afterDelay:0.5];
}
return YES;
}
I tested this code to work in simulator only, let me know if it works on device too ;-)
Do you have the autoResizingMask set on the sub view?
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Something like that should do the trick and allow the view sitting atop the stack to re-size.
The obvious solution, keeping your original architecture, would have been to present that view modally:
- (void)tabBarController:(UITabBarController *)tb
didSelectViewController:(UIViewController *)vc {
if (tb.selectedIndex == MODALONE) {
UIViewController* mod =
[[UIViewController alloc] initWithNibName: #"ModalView"
bundle: nil];
[tb presentModalViewController:mod animated:NO];
[mod release];
}
}
The view now covers the entire screen (except for the status bar is there is one) including the tab bar, so it looks as if the tab bar has gone away in response to the user pressing that tab bar item.
autoresizing mask has an enumeration. Try to set all the options and check if autoresize subviews option is checked in parent view
You can create Tabbar Category and show/Hide easily. and you can access full view.
create category #import "UITabBarController+HideTabBar.h"
#implementation UITabBarController (HideTabBar)
- (void)hideTabBarAnimated:(BOOL)animated
{
CGRect statusbarFrame = [UIApplication sharedApplication].statusBarFrame;
CGRect tabBarControllerFrame = self.view.frame;
if (statusbarFrame.size.height>20)
{
tabBarControllerFrame.size.height = screenSize.size.height + self.tabBar.frame.size.height - 20.0;
}
else
{
tabBarControllerFrame.size.height = screenSize.size.height + self.tabBar.frame.size.height ;
}
if (animated) {
[UIView animateWithDuration:0.2 animations:^{
[self.view setFrame:tabBarControllerFrame];
} completion:^(BOOL finished) {
}];
}
else
[self.view setFrame:tabBarControllerFrame];
}
- (void)showTabBarAnimated:(BOOL)animated {
CGRect statusbarFrame = [UIApplication sharedApplication].statusBarFrame;
CGRect tabBarControllerFrame = self.view.frame;
if (statusbarFrame.size.height>20)
{
tabBarControllerFrame.size.height = screenSize.size.height - 20.0;
}
else
{
tabBarControllerFrame.size.height = screenSize.size.height ;
}
if (animated) {
[UIView animateWithDuration:0.2 animations:^{
[self.view setFrame:tabBarControllerFrame];
} completion:^(BOOL finished) {
}];
}
else
[self.view setFrame:tabBarControllerFrame];
}
#end
Note : use statusbarFrame is used when hotspot or call is ON so tabbar would not cut down.
Now Import category in which you class you want to use methods and just call below methods to hide or show tabbar.
[self.tabBarController hideTabBarAnimated:YES];
[self.tabBarController showTabBarAnimated:YES];
Hope this Helps.
Hope this works.
#interface UITabBarController (Additions)
-(void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated;
#end
#implementation UITabBarController (Additions)
-(void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated
{
if (animated)
{
[UIView beginAnimations:nil context:nil];
}
if (hidden)
{
self.tabBar.frame = CGRectMake(self.tabBar.frame.origin.x, self.tabBar.superview.frame.size.height, self.tabBar.bounds.size.width, self.tabBar.bounds.size.height);
}
else
{
self.tabBar.frame = CGRectMake(self.tabBar.frame.origin.x, self.tabBar.superview.frame.size.height - self.tabBar.frame.size.height + 10, self.tabBar.bounds.size.width, self.tabBar.bounds.size.height);
}
if (animated)
{
[UIView commitAnimations];
}
}
Here is my solution (my tab view controller is inside navigation controller for good measure)... So I have subclassed UITabBarController and did this... exposing -setTabBarHidden: method
- (void)setTabBarHidden:(BOOL)hidden {
_tabBarHidden = hidden;
[UIView performWithoutAnimation:^{
[self adjustViews];
}];
}
- (void)adjustViews {
if ( _tabBarHidden ) {
CGRect f = self.tabBar.frame;
// move tab bar offscreen
f.origin.y = CGRectGetMaxY(self.view.frame);
self.tabBar.frame = f;
// adjust current view frame
self.selectedViewController.view.frame = self.view.frame;
} else {
CGRect f = self.tabBar.frame;
// move tab bar on screen
f.origin.y = CGRectGetMaxY(self.view.frame) - (CGRectGetMaxY(self.tabBar.bounds) + CGRectGetMaxY(self.navigationController.navigationBar.frame));
self.tabBar.frame = f;
// adjust current view frame
f = self.view.bounds;
f.size.height -= CGRectGetMaxY(self.tabBar.bounds);
self.selectedViewController.view.frame = f;
}
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[UIView performWithoutAnimation:^{
[self adjustViews];
}];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[UIView performWithoutAnimation:^{
[self adjustViews];
}];
}
put the statement in the init method of the UIViewController
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.hidesBottomBarWhenPushed = true
setupDependencyConfigurator()
}
See this thread:
Show/Hide TabBarController in iphone
In summary, you can see an example of this behavior in this sample code:
http://developer.apple.com/iphone/library/samplecode/TheElements/index.html
Why are you not using a navigation controller. It's a lot easier to hide the nav bar than the tab bar...
Just made the following code in Monotouch inside a subclass of UITabBarController:
public void ShowTabBar()
{
UIView.BeginAnimations("Anim");
UIView.SetAnimationDuration(0.25f);
this.View.Subviews[0].Frame = new RectangleF(0f, 0f, 320f, 431f);
this.TabBar.Frame = new RectangleF(0f, 431f, 320f, 49f);
this.TabBar.Hidden = false;
UIView.CommitAnimations();
}
public void HideTabBar()
{
UIView.BeginAnimations("Anim");
UIView.SetAnimationDuration(0.25f);
this.View.Subviews[0].Frame = new RectangleF(0f, 0f, 320f, 480f);
this.TabBar.Frame = new RectangleF(0f, 481f, 320f, 510f);
this.TabBar.Hidden = true;
UIView.CommitAnimations();
}

How to resize a tableHeaderView of a UITableView?

I'm having trouble resizing a tableHeaderView. It simple doesn't work.
1) Create a UITableView and UIView (100 x 320 px);
2) Set the UIView as tableHeaderView of the UITableView;
3) Build and Go. Everything is ok.
Now, I want to resizing the tableHeaderView, so I add this code in viewDidLoad:
self.tableView.autoresizesSubviews = YES;
self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;
CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;
The height of the tableHeaderView should appear with 200, but appears with 100.
If I write:
self.tableView.autoresizesSubviews = YES;
CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;
self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;
Then it starts with 200 of height, as I want. But I want to be able to modify it in runtime.
I've also tried this, without success:
self.tableView.autoresizesSubviews = YES;
self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;
CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;
[self.tableView.tableHeaderView setNeedsLayout];
[self.tableView.tableHeaderView setNeedsDisplay];
[self.tableView setNeedsLayout];
[self.tableView setNeedsDisplay];
The point here is: How do we resize a tableHeaderView in runtime ???
Have anyone able to do this?
Thanks
iMe
FYI: I've gotten this to work by modifying the tableHeaderView and re-setting it. In this case, i'm adjusting the size of the tableHeaderView when the UIWebView subview has finished loading.
[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];
This answer is old and apparently doesn't work on iOS 7 and above.
I ran into the same problem, and I also wanted the changes to animate, so I made a subclass of UIView for my header view and added these methods:
- (void)adjustTableHeaderHeight:(NSUInteger)newHeight{
NSUInteger oldHeight = self.frame.size.height;
NSInteger originChange = oldHeight - newHeight;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
newHeight);
for (UIView *view in [(UITableView *)self.superview subviews]) {
if ([view isKindOfClass:[self class]]) {
continue;
}
view.frame = CGRectMake(view.frame.origin.x,
view.frame.origin.y - originChange,
view.frame.size.width,
view.frame.size.height);
}
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
[(UITableView *)self.superview setTableHeaderView:self];
}
This essentially animates all the subviews of the UITableView that aren't the same class type as the calling class. At the end of the animation, it calls setTableHeaderView on the superview (the UITableView) – without this the UITableView contents will jump back the next time the user scrolls. The only limitation I've found on this so far is if the user attempts to scroll the UITableView while the animation is taking place, the scrolling will animate as if the header view hasn't been resized (not a big deal if the animation is quick).
If you want to conditionally animate the changes you can do the following:
- (void) showHeader:(BOOL)show animated:(BOOL)animated{
CGRect closedFrame = CGRectMake(0, 0, self.view.frame.size.width, 0);
CGRect newFrame = show?self.initialFrame:closedFrame;
if(animated){
// The UIView animation block handles the animation of our header view
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// beginUpdates and endUpdates trigger the animation of our cells
[self.tableView beginUpdates];
}
self.headerView.frame = newFrame;
[self.tableView setTableHeaderView:self.headerView];
if(animated){
[self.tableView endUpdates];
[UIView commitAnimations];
}
}
Please note that the animation is two-folded:
The animation of the cells below the tableHeaderView. This is done using beginUpdates and endUpdates
The animation of the actual header view. This is done using a UIView animation block.
In order to synchronize those two animations the animationCurve has to be set to UIViewAnimationCurveEaseInOut and the duration to 0.3, which seems to be what the UITableView uses for it's animation.
Update
I created an Xcode project on gihub, which does this.
Check out the project ResizeTableHeaderViewAnimated in besi/ios-quickies
I think it should work if you just set the height of myHeaderView like so:
CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;
self.tableView.tableHeaderView = myHeaderView;
Used #garrettmoon solution above until iOS 7.
Here's an updated solution based on #garrettmoon's:
- (void)adjustTableHeaderHeight:(NSUInteger)newHeight animated:(BOOL)animated {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:[CATransaction animationDuration]];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
newHeight);
[(UITableView *)self.superview setTableHeaderView:self];
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
[(UITableView *)self.superview setTableHeaderView:self];
}
This worked for me on iOS 7 and 8. This code is running on the table view controller.
[UIView animateWithDuration:0.3 animations:^{
CGRect oldFrame = self.headerView.frame;
self.headerView.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, newHeight);
[self.tableView setTableHeaderView:self.headerView];
}];
Its because the setter of tableHeaderView.
You have to set the UIView height before set the tableHeaderView. (Would be much easier if Apple open sources this framework...)
On iOS 9 and below, tableHeaderView would not re-layout after resizing it.
This issue is resolved in iOS 10.
To solve this issue, just do it with the following code:
self.tableView.tableHeaderView = self.tableView.tableHeaderView;
On iOS 9.x, doing this on viewDidLoad works just fine:
var frame = headerView.frame
frame.size.height = 11 // New size
headerView.frame = frame
headerView is declared as #IBOutlet var headerView: UIView! and connected on the storyboard, where it is placed at the top of the tableView, to function as the tableHeaderView.
This is only for when you use auto-layout and set translatesAutoresizingMaskIntoConstraints = false to a custom header view.
The best and the simplest way is to override intrinsicContentSize. Internally UITableView uses intrinsicContentSize to decide its header/footer size. Once you have override intrinsicContentSize in your custom view, What you need to do is as below
configure the custom header/footer view's layout(subviews)
invoke invalidateIntrinsicContentSize()
invoke tableView.setNeedsLayout() and tableView.layoutIfNeeded()
Then the UITableView's header/footer will be updated as you want. No need to set the view nil or reset.
One thing really interesting for the UITableView.tableHeaderView or .tableFooterView is that UIStackView loose its ability to manage its arrangedSubviews. If you want to use UIStackView as a tableHeaderView or tableFooterView, you have to embed the stackView in a UIView and override UIView's intrinsicContentSize.
For swift 5 Tested code
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let headerView = self.tblProfile.tableHeaderView else {
return
}
let size = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
if headerView.frame.size.height != size.height {
headerView.frame.size.height = size.height
self.tblProfile.tableHeaderView = headerView
self.tblProfile.layoutIfNeeded()
}
}
Note : You need to give all subview's constraints form top, bottom, leading, trailing. So it will get whole required size.
Reference taken from : https://useyourloaf.com/blog/variable-height-table-view-header/
Setting the height for header view property tableView.tableHeaderView in viewDidLoad seems not work, the header view height still not change as expected.
After fighting against this issue for many tries. I found that, you can change the height by invoking the header view create logic inside the
- (void)didMoveToParentViewController:(UIViewController *)parent method.
So the example code would look like this:
- (void)didMoveToParentViewController:(UIViewController *)parent {
[super didMoveToParentViewController:parent];
if ( _tableView.tableHeaderView == nil ) {
UIView *header = [[[UINib nibWithNibName:#"your header view" bundle:nil] instantiateWithOwner:self options:nil] firstObject];
header.frame = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), HeaderViewHeight);
[_tableView setTableHeaderView:header];
}
}
If custom headerView is designed using autolayout and headerView needs to be updated after web-fetch or similar lazy task.
then in iOS-Swift I did this and got my headerView updated using bellow code:
//to reload your cell data
self.tableView.reloadData()
DispatchQueue.main.async {
// this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
I found the initWithFrame initializer of a UIView doesn't properly honor the rect I pass in. Hence, I did the following which worked perfectly:
- (id)initWithFrame:(CGRect)aRect {
CGRect frame = [[UIScreen mainScreen] applicationFrame];
if ((self = [super initWithFrame:CGRectZero])) {
// Ugly initialization behavior - initWithFrame will not properly honor the frame we pass
self.frame = CGRectMake(0, 0, frame.size.width, 200);
// ...
}
}
The advantage of this is it is better encapsulated into your view code.
I have implemented animated height change of the table's header to expand to overall screen when tapped. However, the code can help in other cases:
// Swift
#IBAction func tapped(sender: UITapGestureRecognizer) {
self.tableView.beginUpdates() // Required to update cells.
// Collapse table header to original height
if isHeaderExpandedToFullScreen {
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.scrollView.frame.size.height = 110 // original height in my case is 110
})
}
// Expand table header to overall screen
else {
let screenSize = self.view.frame // "screen" size
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.scrollView.frame.size.height = screenSize.height
})
}
self.tableView.endUpdates() // Required to update cells.
isHeaderExpandedToFullScreen= !isHeaderExpandedToFullScreen // Toggle
}
UITableView resizing header - UISearchBar with Scope Bar
I wanted a UITableView with a UISearchBar as the header to the table so I have a hierarchy that looks like this
UITableView
|
|--> UIView
| |--> UISearchBar
|
|--> UITableViewCells
UISearchBarDelegate methods
As has been stated elsewhere, if you don't setTableViewHeader after changing it, nothing will happen.
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsScopeBar = YES;
[UIView animateWithDuration:0.2f animations:^{
[searchBar sizeToFit];
CGFloat height = CGRectGetHeight(searchBar.frame);
CGRect frame = self.tableView.tableHeaderView.frame;
frame.size.height = height;
self.tableHeaderView.frame = frame;
self.tableView.tableHeaderView = self.tableHeaderView;
}];
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
searchBar.showsScopeBar = NO;
[UIView animateWithDuration:0.f animations:^{
[searchBar sizeToFit];
CGFloat height = CGRectGetHeight(searchBar.frame);
CGRect frame = self.tableView.tableHeaderView.frame;
frame.size.height = height;
self.tableHeaderView.frame = frame;
self.tableView.tableHeaderView = self.tableHeaderView;
}];
[searchBar setShowsCancelButton:NO animated:YES];
return YES;
}
Obviously, by now Apple should have implemented UITableViewAutomaticDimension for tableHeaderView & tableFooterView...
The following seems to work for me using layout contraint(s):
CGSize s = [ self systemLayoutSizeFittingSize : UILayoutFittingCompressedSize ];
CGRect f = [ self frame ];
f.size = s;
[ self setFrame : f ];
If your tableHeaderView is a content adjustable webView,you can try:
[self.webView.scrollView addObserver:self forKeyPath:#"contentSize" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
self.webView.height = self.webView.scrollView.contentSize.height;
self.tableView.tableHeaderView = self.webView;
}
I tested it on iOS9 and iOS11,worked well.
Did you try
[self.tableView reloadData] after changing the height?