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.
Related
Basically, I am including two buttons located below the navigation bar. And below these two buttons, there is a UITableView, with the UISearchBar as its header view. However, when I click the search bar, the animation moves very strange.
Then I try to use animation to move the UITableView together with the search bar to the top,
the animation goes like this
The code added to the table view is like this:
- (BOOL) searchBarShouldBeginEditing:(UISearchBar *)searchBar {
CGRect tableViewFrame = self.myTableView.frame;
tableViewFrame.origin.y = 0;
[UIView animateWithDuration:0.1
animations:^{
self.myTableView.frame = tableViewFrame;
}
completion:nil];
return YES;
}
I am wondering how to move the UISearchBar to the top of the screen, together with the whole table view with smooth animations.
- (BOOL) searchBarShouldBeginEditing:(UISearchBar *)searchBar {
[UIView animateWithDuration:0.1
animations:^{
[ searchBar setFrame:CGRectMake(searchBar.frame.origin.x, 0, searchBar.frame.size.width, searchBar.frame.size.height)];
[self.myTableView setFrame:CGRectMake(myTableView.frame.origin.x, searchBar.frame.size.height, self.myTableView.frame.size.width, myTableView.frame.size.height)];
}
completion:nil];
return YES;
}
try this code
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.
I am trying to make a UITableView appear when a user taps on a button and disappear when the button is re-tapped.
I implemented the following code but nothing seems to appear when I tap the button.
- (IBAction)dropDown:(UIButton *)sender
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.6];
CGAffineTransform transfrom = CGAffineTransformMakeTranslation(0, 200);
self.markersTableView.transform = transfrom;
self.markersTableView.alpha = self.markersTableView.alpha * (-1) + 1;
[UIView commitAnimations];
}
What may potentially be the issue?
EDIT:
I was able to make the UITableView appear and disappear by adding self.markersTableView.hidden = YES; in viewDidLoad() and self.markersTableView.hidden = NO; in the IBAction method.
However, the table view disappears when I initially tap on the button as shown in the screenshot:
The fading of the rows is an indication it is moving down the screen, and then it disappears.
It only reappears when I re-tap on the UIButton the 2nd time.
Any clues?
Don't use a transform on your table view. That will make it LOOK like it's in a different position, but it won't respond to taps correctly.
Instead, use the newer UIView block-based animation methods and change the view's center.
The code might look like this (if you're NOT using auto-layout)
[UIView AnimateWithDuration: .2
animations: ^
{
CGPoint center = self.markersTableView.center;
center.y += 200;
self.markersTableView.center = center;
}
];
If you're using auto-layout, though, that won't work and you will need to animate the view's position using constraints.
From memory, here's an outline of how to do auto-layout based animations: You would create a vertical position constraint on your table view and connect the constraint to an IBOutlet in your view controller. In your animation code you change the constant of the constraint (the vertical position) and then in the animation block, send the view a needsLayout message.
Has anyone tried using a UISearchDisplayController with a UISearchBar that is a UIBarButtonItem in a UIToolbar?
I would appreciate tips on how to do this successfully.
Currently whenever the search controller pops up it redraws the UISearchBar and I'm struggling to maintain a similar look to the UIToolbar
Usually you don't want to put a search bar inside a toolbar, however, it seems you want to do something similar to what I did.
So here is how I did it, it may be called a hack, but it works like a charm :)
First you have to set it up in interface builder like this:
Notice that the search is not a child of toolbar, instead it is above.
The search bar should have "clear color" background and flexible left, right and width autoresizing masks.
You put a 1-pixel label with black background below the toolbar, ie. [x=0, y=44, width=320 or frame width, height=1], also flexible left, right and width autoresizing masks.This is to hide the one visible pixel you get, after the search display controller shows the table view. Try it without it to understand what I mean.
You setup any tool bar items and be sure to have outlets for them, since you will be needing those.
and now for the code ...
when you start searching:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
// animate the search bar to the left ie. x=0
[UIView animateWithDuration:0.25f animations:^{
CGRect frame = controller.searchBar.frame;
frame.origin.x = 0;
controller.searchBar.frame = frame;
}];
// remove all toolbar items
[self.toolbar setItems:nil animated:YES];
}
when you end searching
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
// animate search bar back to its previous position and size
// in my case it was x=55, y=1
// and reduce its width by the amount moved, again 55px
[UIView animateWithDuration:0.25f
delay:0.0f
// the UIViewAnimationOptionLayoutSubviews is IMPORTANT,
// otherwise you get no animation
// but some kind of snap-back movement
options:UIViewAnimationOptionLayoutSubviews
animations:^{
CGRect frame = self.toolbar.frame;
frame.origin.y = 1;
frame.origin.x = 55;
frame.size.width -= 55;
controller.searchBar.frame = frame;
}
completion:^(BOOL finished){
// when finished, insert any tool bar items you had
[self.toolbar setItems:[NSArray arrayWithObject:self.currentLocationButton] animated:YES];
}];
}
With this I get the following with a nice animation :)
This is a strange problem. I have an iPhone view controller for creating a new user with some text fields that require animation to avoid the keyboard when it is shown, i.e. the view animates up and down to keep a minimum clearance between the top of the keyboard and the lower edge of the text field. That worked fine when it was presented modally from the login existing user screen, the initial view controller in the storyboard.
Then I decided to change the app a bit so that the login/create user views would belong to the same view controller. They transition like so:
if(accountCreateView == nil) {
UINib *nib = [UINib nibWithNibName:#"NewAccountView" bundle:nil];
NSArray *nibViews = [nib instantiateWithOwner:self options:nil];
accountCreateView = [nibViews objectAtIndex:0];
}
[UIView transitionFromView:(displayingLoginView ? loginView : accountCreateView)
toView:(displayingLoginView ? accountCreateView : loginView)
duration:0.6
options:(displayingLoginView ?
UIViewAnimationOptionTransitionFlipFromRight :
UIViewAnimationOptionTransitionFlipFromLeft)
completion:^(BOOL finished) {
if (finished) {
displayingLoginView = !displayingLoginView;
}
}
];
This works fine too. However the code that does animation of the views does not. When a text field becomes active the code to check proximity of the text field to the keyboard is called but nothing happens when the animation block executes.
So I checked:
if([UIView areAnimationsEnabled])
NSLog(#"Animations are enabled");
else
NSLog(#"Animations are disabled");
Animations are certainly enabled.
So I moved it back further to viewDidLoad, trying a simple animation to see what works, before anything else:
CGRect viewFrame = loginNameTextField.frame;
viewFrame.origin.y = 400.f;
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
loginNameTextField.frame = viewFrame;
}
completion:NULL];
This works fine! Text field moves slowly down the window.
This does nothing, and that is the confusing part:
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 400.f;
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.frame = viewFrame;
}
completion:NULL];
viewFrame when set from self.view.frame has origin 0,20 and size 320,460 as expected.
I tried setting the frame property directly:
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 400.f;
self.view.frame = viewFrame;
Looks like I can change the frame of subviews of self.view but not of self.view. A fix might be to leave the initial view controller as a blank view in the storyboard and create xibs for both the login view and create user view and load them in viewDidLoad - but why?
edit: Yes, switching the storyboard version of the view controller to a plain empty view and adding the view containing the actual UI from a xib as a subview does make animations work again. Still don't know why though.
If all you need to do is keep your text fields above your keyboard, why not drop the UIViewController and change to a UITableViewController and use static cells? You place one text field per cell (creating enough cells to meet your needs) and style it how you like. When you don't have a first responder and there are few enough cells to fit on the screen, it won't scroll. It there are more than what will fit, then it will scroll to reach the bottom/top cells. Yet no matter how many cells you have, if you select a text field that will be covered up by the keyboard, the device will automatically scroll the cell to a viewable position. It's all built in and I use this feature all the time. It works with text fields and text views. Just remember to comment out the number of sections, number of rows per section, and the cell for index path methods so the static cells will work correctly. It saves a lot of coding.
HTH
Rob