searchbar within tableview - iphone

I am trying to set search bar for table, so can anyone tell me that, is it possible to have uisearchabr when table scroll up / pull up and for other case search bar doesn't get appear on screen. Is it possible? If yes, then how?
Thank you in advance

You can implement scrollViewDelegate scrollViewDidScroll and check the contentOffset to show/hide search bar. Since table view is a subclass of UIScrollView, you can depend on this delegate method to decide when to show/hide it.
Basically when the contentOffset represents the scrolled up position, you can show this search bar and when the contentOffset value starts changing, you can hide the search bar. Use hidden property of the search bar to show/hide it. You can also use removeFromSuperView/addSubview methods.

You can use below code or concept.Concept is in scroll view delegate function you will check the content offset and display the set the search bar object in table view header.
Code :
//MARK: -UIScrollViewDelegate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if (scrollView.contentOffset.y <= - 65.0f) {
[self.tableView setTableHeaderView:self.searchBar];
}
}

Make delegate of UIScrollViewDelegate and implement its delegate method,
in this when you start scroll the table then unhide your searchBar and change frame of tableView.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[mySearchBar setHidden:NO];
[quotesTableView setFrame:CGRectMake(0, 44, 320, 416)];
}

Related

Tabbar Controller with swipe effect

I'm trying to do a Tabbar Controller like below effect:
By swiping an viewcontroller will redirect to next tab. How can we achieve this in iOS? Is there any other controls to do like this?
Just add UISwipeGestureRecognizer to your tabBarView controller and change your tabBar index after swipe.
swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(swipeMethod:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft;
[self addGestureRecognizer:swipeRecognizer];
And my method to handle swipe is :
-(void)swipeMethod: (UISwipeGestureRecognizer *) sender
{
NSLog(#"Swipe!");
}
EDIT
Or you can use UIScrollView with paging enable and UIView to display your data.
Here is the tutorial you are looking for Tabbar Controller with swipte effect
There is a library for this on GitHub, it is called MGSwipeTabBarController and is designed to do exactly what you are looking for.
It is as simple as :
NSArray *viewControllers = . . . //your view controllers
MGSwipeTabBarController *swipeController = [[MGSwipeTabBarController alloc] initWithViewControllers:viewControllers];
Please Note that it is only compatible with iOS7 and + and that you'll still need to design your own tab bar that respond to scroll events using the MGSwipeTabBarControllerDelegateprotocol.
https://github.com/mglagola/MGSwipeTabBarController
https://github.com/nicklockwood/SwipeView
you can use this class to achieve your goal...
or else you have to make animation for tap on tabbar using following method,
[UIView transitionFromView:<#(UIView *)#> toView:<#(UIView *)#> duration:<#(NSTimeInterval)#> options:<#(UIViewAnimationOptions)#> completion:<#^(BOOL finished)completion#>]
If anyone is still looking you can find another implementation here on this youtube series
https://www.youtube.com/watch?v=3Xv1mJvwXok&list=PL0dzCUj1L5JGKdVUtA5xds1zcyzsz7HLj
Edit:
So to my knowledge and according to the video, the idea is that you'll want to use two UICollectionViews in one view controller. One collection view to display the content (apps) and the other for the horizontal navigation containing the categories.
To create the green 'highlight' bar you can use a UIView and adjust the height/width of the bar using constraints - heightAnchor/widthAnchor and add that to the navigation bar.
To get the bar moving with the distance the user will swipe, there is a method you can override to capture the horizontal scrolling called scrollViewDidScroll. From here you'll want to provide a variable from your the UIView's constraint (of type NSLayoutConstraint) to be able to update the x position of the UIView
override func scrollViewDidScroll(_ scrollView: UIScrollView)
{
print(scrollView.contentOffset.x)
menuBar.myGreenBarLeftConstraint.constant = scrollView.contentOffset.x / 4
//or however many categories you have
}

Find out whether UITableView is scrolled to top

I am using scrollToRowAtIndexPath: to scroll UITableView to top. Then I handle the animation in scrollViewDidEndScrollingAnimation:. After it scrolls, it should perform an action. My problem is, that when it doesn't scroll - e.g. the table view is already on top before I call the method - the action doesn't get called in scrollViewDidEndScrollingAnimation:. How do I find out whether the UITableView is already on top?
if (yourTableView.contentOffset.y > 0)
{
// yourTableView is not on top.
}
else
{
// yourTableView is already on top.
}
Use UITableView contentOffset property. If contentOffset.y is 0 then table is at top else it is not.
Hope it helps you.
You need to use the UIScrollViewDelegate function - (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView and work out if the content offset is set to 0 on the y axis for that scrollview. If its 0 then you have reached the top.
while you're scrolling up tableView(_:cellForRowAt) gets called to display rows and when the indexPath.row == 0 that's when you're at the top of the tableview

Scroll to selected tablecell

I implemented a TableView to show up a PickerView when a particular row is selected. But that would sometime block the selected cell. So, I want my scrollView to scroll to the selected cell when the pickerView shows up.
Is there anyway to get the current location of the selected row? Such that I can implement something like
//---scroll to the current text field---
CGRect textFieldRect = [currentTextField frame];
[scrollView scrollRectToVisible:textFieldRect animated:YES];
Thanks.
If you want to solve the pickerView or the keyboard hiding the screen, you can try this approach. Implement the heightForFooterInSection and set a height value, and the tableView will scroll up to the same value as you specify there.
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 70.0;
}
If you just want the tableView to scroll , just implement the scrollToRowAtIndexPath:atScrollPosition:animated:
Edit:
Since you are using a UIScrollView, you can programmatically scroll to a certain region using
[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
Also read through this reference: http://www.aaron.griffith.name/weblog/2011/02/23/scrolling-a-uiscrollview-programmatically/

IPhone Application Scroll to given position in UITableView when page loaded

I want to scroll down to given row in my table view.
if I use following code inside a button event it works correctly.
[planTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:0 ] atScrollPosition:0 animated:YES];
But I want to do it just after the page load. Placing above code inside viewDidLoad or viewDidAppear did not work.
Any help??
it's kinda hack, but you also might want to perform the -scrollToRowAtIndexPath:atScrollPosition:animated: with some delay, because when either -viewDidLoad or -viewDidAppear: is called, table view rows haven't been created yet so there's nothing to scroll to.
so:
- (void)doScrolling
{
[planTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:0 ] atScrollPosition:0 animated:YES];
}
and in -viewDidAppear:
[self performSelector:#selector(doScrolling) withObject:nil afterDelay:0.3];
also pay attention to atScrollPosition: argument. it's enum actually:
typedef enum {
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
} UITableViewScrollPosition;
so if the row is visible and 0 is passed, no scrolling will be performed
UITableView is a subclass of UIScrollView, so you can just set the contentOffset of your tableView in viewDidLoad: or viewWillAppear.
If you need to scroll 7 table view cells down in length, calculate the height of these 7 cells (the default is 44px, but if you have custom cell heights you need to factor that in) and set the contentOffset to CGPointMake(0, *calculated height*). In the case of 7 44px height cells, it would be CGPointMake(0, 308).

Changing the size of the UISearchBar TextField?

I have a UITableView with an Index on the side; I want to add a UISearchBar to it, but the index overlaps with the "x" to clear the search. I've noticed in the Contacts application, the textfield within the UISearchBar is resized to accommodate this, but I can't work out how to do this in my own app.
I have tried the following in my viewDidLoad, but it does not seem to work.
UITextField * textField = (UITextField *)[[self.search subviews] objectAtIndex:0];
CGRect r = textField.frame;
[textField setFrame:CGRectMake(r.origin.x, r.origin.y, r.size.height, r.size.width-30)];
Any ideas?
it's much easier than all these suggestions. In interface builder, instead of putting the Search Bar as the header of your Table View, you can put a View instead. Then, put a Navigation Bar inside this View. Grab the left resizing handle of the Navigation Bar and pull it to the right until the N B is only 25 pixels wide. Clear out the Title in the N B (double click to select it, then delete). Then, add a Search Bar into the same View. Move its right resizing handle to the left, adjust so that it abuts the N B. That's it.
You can enable a cancel button if you want too and it also won't overlap the index (remains within the search bar).
Apparently a Table View can only have 1 subview in its header, that's why you need to put the View first, then the N B and Search Bar inside it.
UPDATE: see Beginning iPhone Development from Apress, p. 241 of SDK 3 edition. You just disable the index while searching.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (isSearching) {
return nil;
}
return keys;
}
Also they talk about adding a magnifying glass to the top of the index.
Great book all around.
Why not just make the actual UISearchBar smaller horizontally, and place an (empty) UINavigationBar to the right of it? They will render the exact same background.
Better than hacking the internals of Apple's objects that could change.
Also, when animating the UISearchBar's width, you'll notice that the inner text field is not animated along with it. You can fix this by calling UISearchBar's "layoutSubviews" within your animation block after changing its frame. (that's where it determines the size of the inner text field)
Ok, I've come up with a solution.
Create a subclass of UISearchBar
Include this code in the drawRect: method.
UITextView * textField = [self.subviews objectAtIndex:0];
textField.frame = CGRectMake(5, 6, (310 - kRightSideMargin), 31);
[super drawRect:rect];
Note: kRightSideMargin is a constant I set in my header file; I have it set to 25.
Thanks for the suggestions from everyone else.
As Padraig pointed out all you have to do is subclass out the searchBar. Create your UISearchBar subclass, and add the following code into the layoutSubviews method:
- (void)layoutSubviews
{
UITextField *searchField;
for(int i = 0; i < [self.subviews count]; i++)
{
if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
searchField = [self.subviews objectAtIndex:i];
}
}
if(!(searchField == nil))
{
searchField.frame = CGRectMake(4, 5, 285, 30);
}
}
This loops through all the subviews and checks them against type UITextField. That way if it ever moves in its line up of subviews this will still grab it. I found 285 to just wide enough not to overlap with the index of my tableView.
As of iOS 6, the navigation bar solution didn't work well for me because of slightly different looks now between the UISearchBar and UINavigationBar. So, I switched to something similar to Padraig's approach by subclassing the UISearchBar.
#interface SearchBarWithPad : UISearchBar
#end
#implementation SearchBarWithPad
- (void) layoutSubviews {
[super layoutSubviews];
NSInteger pad = 50;
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]])
view.frame = CGRectMake (view.frame.origin.x, view.frame.origin.y, view.frame.size.width - pad, view.frame.size.height);
}
}
#end
Edit: Ah, I haven't tried it, but I think you might be able to set a navigation bar's clipToBounds = YES to turn off it's new shadow, thereby creating a consistent look again between the two controls.
I am using ViewDeck and want to show a UISearchbar inside the leftController.
Now the problem is if I open the left side which contains the navigation, the right bit overlaps my search field.
I got rid of this by over writing UISearchBar, the textfield will always have the same width, but in one case there is the ViewDeck overlapping and in the other case I hide the ViewDeck-bit and then the cancel button will take up the space:
Subclassing UISearchBar
#import "ViewDeckSearchBar.h"
#define kViewDeckPadding 55
#interface ViewDeckSearchBar()
#property (readonly) UITextField *textField;
#end
#implementation ViewDeckSearchBar
static CGRect initialTextFieldFrame;
- (void) layoutSubviews {
[super layoutSubviews];
// Store the initial frame for the the text field
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initialTextFieldFrame = self.textField.frame;
});
[self updateTextFieldFrame];
}
-(void)updateTextFieldFrame{
int width = initialTextFieldFrame.size.width - (kViewDeckPadding + 6);
CGRect newFrame = CGRectMake (self.textField.frame.origin.x,
self.textField.frame.origin.y,
width,
self.textField.frame.size.height);
self.textField.frame = newFrame;
}
-(UITextField *)textField{
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]]){
return (UITextField *)view;
}
}
return nil;
}
#end
ViewController class
In my Navigation class I need to overwrite these two UISearchbarDelegate methods in order to go to fullscreen with the search results:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
[self.viewDeckController setLeftSize:0];
// I am also using scopes, which works fine (they fade out when not searching)
self.searchBar.scopeButtonTitles = #[#"Food",
#"Beverages",
#"Misc"];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
self.viewDeckController.leftSize = 55;
}
Result
ViewDeck showing to the right:
(source: minus.com)
Search in Fullscreen (The button and the scope buttons are animated in).
(source: minus.com)
searchBar.layoutMargins = UIEdgeInsetsMake(0, 0, 0, rightPad);
My old solution of changing the UITextField frame stopped working in iOS 13. Putting a UINavigationBar to the right of the UISearchBar never worked well for me as they had different looks at top and bottom.
Sorry to drag this all up again.
I wanted the UISearchBar to be shorter, and I'm using a UISearchBarController, but without actually wanting the index. This is because I have an overlay to the right:
To do this, I fake a sectionIndex with one blank item, then hide it. Here's how I do that:
- (void)hideTableIndex {
for (UIView *view in [tableView subviews]) {
if ([view isKindOfClass:NSClassFromString(#"UITableViewIndex")]) {
view.hidden = YES;
}
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)aTableView {
if (aTableView == self.searchDisplayController.searchResultsTableView) {
return nil;
} else {
[self performSelector:#selector(hideTableIndex) withObject:nil afterDelay:0];
return [NSArray arrayWithObjects:#"", nil];
}
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return 0;
}
This shortens the the UISearchBar and hides the index so it can't be tapped (a small section would otherwise hand to the left of the overlay that when tapped would scroll the UITableView to the top). Like this:
Best of all, when you use the search, you still get the full width bar:
Just put a UIView and put the search bar inside that UIView. UIView must be of same size as UISearchBar.
this worked for me.
The text field used in UISearchBar is a subclass of UITextField called UISearchBarTextField.
AFAIK, there's no way to resize a UISearchBarTextField using the public API, and the private API doesn't reveal much either.
Maybe you can take a look at UISearchBarTextField's subviews, if it has any.
UPDATE: It doesn't.
UPDATE 2: I think you should take a look at UITextField's rightView property. The below code, although it doesn't work, seems like a good starting point:
UIView *emptyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[textField setRightView:emptyView];
[textField setRightViewMode:UITextFieldViewModeAlways];
[emptyView release];
Sorry for Necroposting, but I found another way to make a little space on the right of the textfield.
I was having the problem, that I had an indexed tableview with a searchbar as the first row. Now the index and the searchbar (made in IB, btw.) were overlapping. It tried almost everything with no success. It seems that the width and height properties of the textifield don't respond... So I came up with this:
searchBar.showsCancelButton = YES;
UIView *cButton = [searchBar.subviews objectAtIndex:2];
cButton.hidden = YES;
I still can't adjust the size of the space, but this does it for now... although... pretty weird solution...
Everyone has provided ways to modify the UI. I have discovered how to obtain identical results. You must provide the following two implementations:
Use UISearchDisplayController
More importantly, make sure you initialize it with:
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController
Failure to set a valid UISearchBar (or passing nil) will prevent the adjustment of the UITextField for the index.
You must return a valid array of titles by implementing:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
If you return nil, the index will not be displayed, and the UITextField will not be properly adjusted.
I've submitted a bug report to Apple, suggesting that it seems logical that only #2 should be required, not #1. I have found nothing in the Human Interface Guideline (iPhone HIG) requiring use of the UISearchDisplayController.
The key is to use the "Search Bar and Search Display Controller" and not the "Search Bar" when using Interface Builder.
It kind of looks as though Apple resize the view (note that the index is animated to the right, off screen), making it bigger than the screen.
I would imagine that you'd need to implement the searchBarTextDidBeginEditing: method of the UISearchBarDelegate to trigger this at the appropriate point. This does, however, feel a bit hacky do maybe there's a better way of doing it.
Another appraoch (though tedious) would be to resize the search bar and fill the 'gap' with a navigation bar. Works for me.
What I've come up with isn't too much better. Basically, I make an empty view with the frame that I want to use for the search bar. Then I create a UIToolbar to go behind the search bar. Be sure to set its frame to the same frame as the UIView, except that the Y value has to be -1; otherwise, you'll get two borders drawn at the top. Next create your UISearchBar, but set the frame's width to 30 (or whatever makes sense for your app) less than the UIView. Add them as subviews and set your UIView as the tableHeaderView.
I followed Mike's advice by making a UIView, then putting a Navigation Bar and UISearch Bar inside it. Only problem is first time the search bar is shown its background is the same as a Navigation Bar normally?
Interestingly, if I activate the search, then click cancel the background of this 'fixed'!?
I'm using SDK 3.0, so I removed the UISearchBar item made when I dragged a UISearchDisplayController in to my NIB, then made the view as described above and wired it up to the file owner and the searchBar outlet in the search display controller.
It work fine!!!
[searchBar setContentInset:UIEdgeInsetsMake(5, 0, 5, 35)];