Skip to content

Instantly share code, notes, and snippets.

@keicoder
Created March 7, 2014 02:40
Show Gist options
  • Save keicoder/9404097 to your computer and use it in GitHub Desktop.
Save keicoder/9404097 to your computer and use it in GitHub Desktop.
objective-c : making custom SearchBar
//making custom SearchBar
//SSAppDelegate.h
@interface SSAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//SSAppDelegate.m
@implementation SSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
@end
//SSSearchBar.h
#import <UIKit/UIKit.h>
@protocol SSSearchBarDelegate;
//A clean, easy to use, awesome replacement for UISearchBar.
@interface SSSearchBar : UIView
//Wrappers around the Textfield subview
@property (nonatomic) NSString *text;
@property (nonatomic) UIFont *font;
@property (nonatomic) NSString *placeholder;
//The text field subview
@property (nonatomic) UITextField *textField;
@property (nonatomic, getter = isCancelButtonHidden) BOOL cancelButtonHidden; //NO by Default
@property (nonatomic, weak) id <SSSearchBarDelegate> delegate;
@end
@protocol SSSearchBarDelegate <NSObject>
@optional
- (void)searchBarCancelButtonClicked:(SSSearchBar *)searchBar;
- (void)searchBarSearchButtonClicked:(SSSearchBar *)searchBar;
- (BOOL)searchBarShouldBeginEditing:(SSSearchBar *)searchBar;
- (void)searchBarTextDidBeginEditing:(SSSearchBar *)searchBar;
- (void)searchBarTextDidEndEditing:(SSSearchBar *)searchBar;
- (void)searchBar:(SSSearchBar *)searchBar textDidChange:(NSString *)searchText;
@end
//A rounded view that makes up the background of the search bar.
@interface SSRoundedView : UIView
@end
//SSSearchBar.m
#import "SSSearchBar.h"
//I like these values; Feel free to play around though :-)
#define kXMargin 8
#define kYMargin 4
#define kIconSize 16
#define kSearchBarHeight 32
@interface SSSearchBar () <UITextFieldDelegate>
{
BOOL _cancelButtonHidden;
}
@property (nonatomic) UIButton *cancelButton;
@property (nonatomic) UIImageView *searchImageView;
@property (nonatomic) SSRoundedView *backgroundView;
@property (nonatomic) UIImage *searchImage;
@end
@implementation SSSearchBar
#pragma mark - Initializers
- (void)setDefaults {
UIImage *searchIcon = [UIImage imageNamed:@"search-icon"];
_searchImage = searchIcon;
self.backgroundColor = [UIColor clearColor];
NSUInteger boundsWidth = self.bounds.size.width;
NSUInteger textFieldHeight = self.bounds.size.height - kYMargin;
//Background Rounded White Image
self.backgroundView = [[SSRoundedView alloc] initWithFrame:CGRectMake(0, 0, boundsWidth, self.bounds.size.height)];
[self addSubview:self.backgroundView];
//Search Image
self.searchImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kIconSize, kIconSize)];
self.searchImageView.image = self.searchImage;
self.searchImageView.contentMode = UIViewContentModeScaleAspectFit;
self.searchImageView.center = CGPointMake(kIconSize/2 + kXMargin, CGRectGetMidY(self.bounds));
[self addSubview:self.searchImageView];
//TextField
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(2*kXMargin + kIconSize, kYMargin, boundsWidth - 4*kXMargin - 2*kIconSize, textFieldHeight)];
self.textField.delegate = self;
self.textField.returnKeyType = UIReturnKeySearch;
self.textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.textField.autocorrectionType = UITextAutocorrectionTypeNo;
UIFont *defaultFont = [UIFont fontWithName:@"Avenir Next" size:14];
self.textField.font = defaultFont;
self.textField.textColor = [UIColor blackColor];
[self addSubview:self.textField];
//Cancel Button
self.cancelButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kIconSize, kIconSize)];
[self.cancelButton setImage:[UIImage imageNamed:@"close-icon"] forState:UIControlStateNormal];
self.cancelButton.contentMode = UIViewContentModeScaleAspectFit;
self.cancelButton.center = CGPointMake(boundsWidth - (kIconSize/2 + kXMargin), CGRectGetMidY(self.bounds));
[self.cancelButton addTarget:self action:@selector(pressedCancel:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.cancelButton];
//Listen to text changes
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextFieldTextDidChangeNotification object:self.textField];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setDefaults];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
CGRect newFrame = frame;
frame.size.height = kSearchBarHeight;
frame = newFrame;
self = [super initWithFrame:frame];
if (self) {
[self setDefaults];
}
return self;
}
- (id)init
{
return [self initWithFrame:CGRectMake(10, 20, 300, 32)];
}
#pragma mark - Properties and actions
- (NSString *)text {
return self.textField.text;
}
- (void)setText:(NSString *)text {
self.textField.text = text;
}
- (NSString *)placeholder {
return self.textField.placeholder;
}
- (void)setPlaceholder:(NSString *)placeholder {
self.textField.placeholder = placeholder;
}
- (UIFont *)font {
return self.textField.font;
}
- (void)setFont:(UIFont *)font {
self.textField.font = font;
}
- (BOOL)isCancelButtonHidden {
return _cancelButtonHidden;
}
- (void)setCancelButtonHidden:(BOOL)cancelButtonHidden {
if (_cancelButtonHidden != cancelButtonHidden) {
_cancelButtonHidden = cancelButtonHidden;
self.cancelButton.hidden = cancelButtonHidden;
}
}
- (void)pressedCancel: (id)sender {
if ([self.delegate respondsToSelector:@selector(searchBarCancelButtonClicked:)])
[self.delegate searchBarCancelButtonClicked:self];
}
#pragma mark - Text Delegate
- (void)textChanged: (id)sender {
if ([self.delegate respondsToSelector:@selector(searchBar:textDidChange:)])
[self.delegate searchBar:self textDidChange:self.text];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if ([self.delegate respondsToSelector:@selector(searchBarShouldBeginEditing:)])
return [self.delegate searchBarShouldBeginEditing:self];
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if ([self.delegate respondsToSelector:@selector(searchBarTextDidBeginEditing:)])
[self.delegate searchBarTextDidBeginEditing:self];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ([self.delegate respondsToSelector:@selector(searchBarTextDidEndEditing:)])
[self.delegate searchBarTextDidEndEditing:self];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([self.delegate respondsToSelector:@selector(searchBarSearchButtonClicked:)])
[self.delegate searchBarSearchButtonClicked:self];
return YES;
}
- (BOOL)isFirstResponder {
return [self.textField isFirstResponder];
}
- (BOOL)becomeFirstResponder {
return [self.textField becomeFirstResponder];
}
- (BOOL)resignFirstResponder {
[self.textField resignFirstResponder];
return YES;
}
#pragma mark - Cleanup
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
@implementation SSRoundedView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(contextRef, [UIColor whiteColor].CGColor);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:18];
[path fill];
}
@end
//SSViewController.h
#import <UIKit/UIKit.h>
@interface SSViewController : UIViewController
@end
//SSViewController.m
#import "SSViewController.h"
#import "SSSearchBar.h"
@interface SSViewController () <SSSearchBarDelegate>
@property (weak, nonatomic) IBOutlet SSSearchBar *searchBar;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic) NSArray *data;
@property (nonatomic) NSArray *searchData;
@end
@implementation SSViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar.cancelButtonHidden = NO;
self.searchBar.placeholder = NSLocalizedString(@"Search text here!", nil);
self.searchBar.delegate = self;
[self.searchBar becomeFirstResponder];
self.data = @[ @"Hey there!", @"This is a custom UISearchBar.", @"And it's really easy to use...", @"Sweet!" ];
self.searchData = self.data;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
#pragma mark - SSSearchBarDelegate
- (void)searchBarCancelButtonClicked:(SSSearchBar *)searchBar
{
self.searchBar.text = @"";
[self filterTableViewWithText:self.searchBar.text];
}
- (void)searchBarSearchButtonClicked:(SSSearchBar *)searchBar
{
[self.searchBar resignFirstResponder];
}
- (void)searchBar:(SSSearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self filterTableViewWithText:searchText];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.searchData count];
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
[self customiseTableViewCell:cell atIndexPath:indexPath];
cell.textLabel.text = self.searchData[indexPath.row];
cell.textLabel.font = [UIFont fontWithName:@"Avenir Next" size:14];
cell.textLabel.textColor = [UIColor whiteColor];
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Helper Methods
- (void)filterTableViewWithText:(NSString *)searchText
{
if ([searchText isEqualToString:@""]) {
self.searchData = self.data;
} else {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self CONTAINS[cd] %@", searchText];
self.searchData = [self.data filteredArrayUsingPredicate:predicate];
}
[self.tableView reloadData];
}
- (void)customiseTableViewCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
//Some fancy stuff - This really isn't needed and isn't the best way to do it. Subclass UITableViewCell if you want something like this.
UIView *backgroundColorView = [cell.contentView viewWithTag:10];
CGRect backgroundFrame = CGRectMake(2, 2, cell.bounds.size.width - 4, cell.bounds.size.height - 2 - (indexPath.row == self.searchData.count - 1? 2:0));
if (!backgroundColorView) {
backgroundColorView = [[UIView alloc] initWithFrame:backgroundFrame];
backgroundColorView.tag = 10;
backgroundColorView.backgroundColor = self.view.backgroundColor;
[cell.contentView insertSubview:backgroundColorView atIndex:0];
cell.textLabel.backgroundColor = [UIColor clearColor];
}
else {
backgroundColorView.frame = backgroundFrame;
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment