How can I add a UIDatePicker Subview with working user interaction - iphone

I have a view based application which has some textboxes that I'm trying to populate with some pickers. For example, one of them will be for date selection. I'm using the following to add a new view to the bottom of my current view, then scroll the entire view upwards:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if(textField == [self date]) {
editingDate = YES;
UIDatePicker *pv = [[UIDatePicker alloc] initWithFrame:CGRectMake(0,460,0,0)];
pv.userInteractionEnabled = YES;
[self.view addSubview:pv];
textField.placeholder = #"currently selecting below";
[self scrollTheView:YES];
return NO;
}
return YES;
}
My scrollTheView method executes as follows:
- (void)scrollTheView:(BOOL) moveUp {
int scrollAmount = 212;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = self.view.frame;
if(moveUp){
rect.origin.y -= scrollAmount;
}
else {
rect.origin.y += scrollAmount;
}
self.view.frame = rect;
[UIView commitAnimations];
}
My problem is that although the display looks perfect, the datepicker control will not accept my input at all. It is simply stuck on the current date. I'm not sure what I'm missing here, probably something simple.

By modifying the code above to do the following to add the subview as a subview of the superview:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 480, 320, 216)];
UIDatePicker *pv = [[UIDatePicker alloc] initWithFrame:CGRectMake(0,0,320,216)];
[myView addSubview:pv];
[self.view.superview addSubview:myView];
and modifying my scroll method to additionally scroll this new view:
UIView *sv = self.view.superview;
UIView *subv = [[sv subviews] objectAtIndex:1];
CGRect rect2 = subv.frame;
if(moveUp){
rect2.origin.y -= scrollAmount;
}
else {
rect2.origin.y += scrollAmount;
}
subv.frame = rect2;
I was able to achieve the goal. Thanks to Ben for the assistance.

It sounds from what you've described that you're placing your UIDatePicker inside of another view, but outside of its bounds. If "Clips subviews" in IB is not checked, then you'll still be able to SEE your picker, but since it's not in the bounds area, it will not be touchable.

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.

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;
}];
}

UITableViewController with picker view

I've a serious problem, and I cannot solve it by myself. I've spent hours searching the documentations, programming guides as well as developer forums and stack overflow.
The problem is I want to display a picker view in UITableViewController. I have a screen that has multiple text fields allowing me to search by title/author/keywords... and I'd also like to specify the minimum and maximum dates, using the UIDatePicker (or UIPickerView - to specify "last 5 days" for example).
I want to use UITableViewController because it saves me a lot of time resizing the table while the keyboard pops up when user presses the text field. In fact I've never been able to reproduce this animation using UIViewController and listening to textfields' delegate. It was almost perfect but there were some visible disadvantages comparing to the behaviour of table if displayed using UITableViewController.
So everything's fine when there are only textfields. But what about the date fileds? I want to make it exactly like the Contacts.app by Apple when I want to add a new contact and specify the birthday. In that application the Date Picker is shown, the table is resized, switching between email/phone field and birthday works great. I could believe that the date picker is in this case the keyboard but not for typing phone/email but date because it slides in/out just like a keyboard and is replaced instantly when the keyboard/picker is opened.
How did thet accomplished it?
Or where can I find the easiest solution to reproduce it. I believe it cannot be as hard because it's very common situation.
Regards
Chris
All of that is pointless. We should deal with the inputView and inputAccessoryView, where inputView should has the picker and inputAccessoryView the toolbar.
You're going to have to create a UIWindow object, then add a view. The windowLevel property makes it higher than the statusBar, which you may or may not want.
//statusWindow is a UIWindow ivar declared in the header
//pickerShowing is declared as a BOOL in header
//release and removeFromSuperview is done in the animation delegate methods
//ANIMATE IN
-(void)slideIn {
CGRect pickerFrame = CGRectMake(0.0f, 0.0f, 320.0f, 200.0f); //guessing on height
UIView *viewForPicker = [[UIView alloc] init];
UIPickerView *aPicker = [[UIPickerView alloc] init]; //don't forget to set delegate and dataSource
viewForPicker.frame = pickerFrame;
statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0.0, 480.0, 320.0f, 200.0f)];//guessing on height, y value is off the screen (bottom)
statusWindow.windowLevel = UIWindowLevelStatusBar;
statusWindow.hidden = NO;
statusWindow.backgroundColor = [UIColor clearColor];
[statusWindow makeKeyAndVisible];
[viewForPicker addSubview:aPicker];
[statusWindow addSubview:viewForPicker];
[viewForPicker release];
[aPicker release];
[UIView beginAnimations:#"slideUp" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:)];
statusWindow.frame = CGRectMake(0.0f, 200.0f, 320.0f, 200.0f); //guessing on y and height values, change them to suit needs
[UIView commitAnimations];
pickerShowing = YES;
}
//ANIMATE out:
-(void)slideOut {
[UIView beginAnimations:#"slideDown" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:)];
statusWindow.frame = CGRectMake(0.0f, 480.0f, 320.0f, 200.0f);
[UIView commitAnimations];
pickerShowing = NO;
}
-(void)animationFinished:(NSString *)name {
if ([name isEqualToString:#"slideDown"]) {
[statusWindow release];
}
}
If you want to slide in/out the picker view, you can use Core Animation.
Simplest snippet:
// Slide picker view in
[UIView beginAnimations: #"SlideIn" context: nil];
myPickerView.frame = upFrame;
[UIView commitAnimations];
// ...
// Slide picker view out
[UIView beginAnimations: #"SlideOut" context: nil];
myPickerView.frame = downFrame;
[UIView commitAnimations];
upFrame and downFrame are CGRect you make with the right position for your picker view on screen and off screen respectively.
Hope this helps.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *targetCell = [tableView cellForRowAtIndexPath:indexPath];
self.pickerView.date = [self.dateFormatter dateFromString:targetCell.detailTextLabel.text];
// check if our date picker is already on screen
if (self.pickerView.superview == nil)
{
[self.view.window addSubview: self.pickerView];
// size up the picker view to our screen and compute the start/end frame origin for our slide up animation
//
// 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.frame = 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.frame = pickerRect;
// shrink the table vertical size to make room for the date picker
CGRect newFrame = self.tableView.frame;
newFrame.size.height -= self.pickerView.frame.size.height;
self.tableView.frame = newFrame;
[UIView commitAnimations];
// add the "Done" button to the nav bar
self.navigationItem.rightBarButtonItem = self.doneButton;
}
}
- (void)slideDownDidStop
{
// the date picker has finished sliding downwards, so remove it
[self.pickerView removeFromSuperview];
}
- (IBAction)dateAction:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.detailTextLabel.text = [self.dateFormatter stringFromDate:self.pickerView.date];
}
- (IBAction)doneAction:(id)sender
{
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGRect endFrame = self.pickerView.frame;
endFrame.origin.y = screenRect.origin.y + screenRect.size.height;
// start the slide down 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];
[UIView setAnimationDidStopSelector:#selector(slideDownDidStop)];
self.pickerView.frame = endFrame;
[UIView commitAnimations];
// grow the table back again in vertical size to make room for the date picker
CGRect newFrame = self.tableView.frame;
newFrame.size.height += self.pickerView.frame.size.height;
self.tableView.frame = newFrame;
// remove the "Done" button in the nav bar
self.navigationItem.rightBarButtonItem = nil;
// deselect the current table row
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
You can download a full working sample app from Apple demonstrating just this.
http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html

How to add a moving text in iPhone

I want to add some text which is a long text lets say a story and I want it to be presented in a moving up fashion. That is it will be displayed in a box and the text will be moved line by line to show the whole story. So one line gets out of the box from top and other comes from the bottom. Like a HTML marquee behavior.
You should look into whether or not UIScrollView's contentOffset property is animatable using UIView animation blocks.
If it's not, then you could try using an NSTimer and in its function, either set the contentOffset or call [scrollView scrollRectToVisible:desiredContentFrame animated:YES]; where desiredContentFrame.origin.y is just a little bit lower than what you previously had it at (depending on the scroll speed you want). Then play around with the firing frequency of your timer and the desiredContentFrame.origin.y's delta to see what looks best and has the best performance.
Here's a quick hack showing both ways:
- (void)startAnimTimer
{
currentRect = CGRectMake(0, 0, 1, 1);
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(doScroll) userInfo:nil repeats:YES];
}
- (void)startAnimUIView
{
[UIView beginAnimations:#"scrollUIViewAnim" context:nil];
[UIView setAnimationDuration:20.0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint newContentOffset = CGPointMake(0, scrollView.contentSize.height);
scrollView.contentOffset = newContentOffset;
[UIView commitAnimations];
}
- (void)loadView {
[super loadView];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(5, 5, 200, 200)];
scrollView.contentSize = CGSizeMake(200, 1000);
scrollView.backgroundColor = [UIColor magentaColor];
CGFloat y = 10;
CGFloat yDelta = 21;
for(int i = 0; i < 47; i++)
{
// Add some UILabels to the scrollview just so we can see it animating
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, 180, 20)];
label.text = [NSString stringWithFormat:#"Cheezburger %d", i];
[scrollView addSubview:label];
[label release];
y += yDelta;
}
[self.view addSubview:scrollView];
// Comment out one of these
//[self startAnimTimer];
[self startAnimUIView];
}
- (void)doScroll
{
CGFloat scrollDelta = 1.0f;
CGRect newRect = CGRectMake(0, currentRect.origin.y + scrollDelta, currentRect.size.width, currentRect.size.height);
// Scroll the scrollview to the next position
[scrollView scrollRectToVisible:newRect animated:YES];
currentRect = newRect;
}
This method may help (or not):
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
If not, just make a big UILabel and animate its frame using a CABasicAnimation.
I think you want to look at the Scroll View (UIScrollView) in the iPhone SDK.
http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
Depending on your implementation, you may not be able to use it "out of the box" but it should provide the functionality you seem to be describing. I'm not sure it will do the auto-scroll thing but that should be pretty easy to implement... maybe.... But, I'm still confident it could be done.

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();
}