Adding a UISegmentedControl to UISearchBar instead of Scope Buttons - ios

I'd like to add scope buttons below my UISearchBar. However I cannot change the tint color of the built in scope buttons.
Instead, I added a UISegmentedControl to my tableViewHeader. This works well enough, but it only shows when I am not typing into the UISearchbar. Not very convenient.
When I enter text into the UISearchBar, the table and segmented controls become hidden by the "no results shown" semi-opaque black layer. Once results start showing my segmented control disappears altogether, and only cells with results show.
I want to make the segmented control clickable during text entry into the search bar.
Do you know of any way to do the following?
make UISegmentedControl move with UISearchBar when text is being entered, or
show UISegmentedControl whilst search results are displayed on the UITableView
Thank you

try
#implementation UISearchBar (subviewAccess)
- (UISegmentedControl *)scopeBar {
for (UIView *v in [self subviews]) {
if ([v isKindOfClass:[UISegmentedControl class]])
return v;
}
return nil;
}
#end
to get hold of the segmented control you want, and tint it from there
(it's currently at index 0, but that's definitely not for sure)
there is no "private API" being used, so apple should be okay with it,
but note if they changed their view layout (unlikely), this could break,
which would have the side effect of your tint disappearing, you should
access the rest of its state through the standard search bar APIs

Related

iOS change custom bar button text color when the button becomes available

So I have a registration page (and multiple other places through the registration process where this will be implemented) that has a Next button, which is set up as a custom UIButton dragged onto the nav bar. As users enter in their registration information, I want to change the color of the text from grey when it is unavailable, to a custom green color. I've read some other threads, such as this one , but they haven't been any help. I think I'm doing what they told me to correctly, but I'm getting different results than I want. Right now my code looks like this:
-(void)checkCompletion
{
if( emailEntered && passwordEntered && [_password.text length] >= 5)
{
[_nextBarButtonItem setEnabled:YES];
[_nextButton setEnabled:YES];
[_nextButton.titleLabel setTextColor:[UIColor customGreen]];
[_nextButton setTintColor:[UIColor customGreen]];
[_nextBarButtonItem setTintColor:[UIColor customGreen]];
nextAvailable = YES;
}
else
{
nextAvailable = NO;
}
}
_nextBarButtonItem is the barButtonItem, and _nextButton is the UIButton I dragged onto the navigation bar, which is underneath _nextBarBUttonItem in the hierarchy. customGreen is a category with its header file #include'd into my prefix.pch, as I use the color throughout the app. This function gets called when textfields return and when the password is edited, so I can make the button available before the return key is pressed if users don't want to dismiss the keyboard first.
I have tried several methods, such as making the button my customGreen on the storyboard and disabling both the barButtonItem and the button itself underneath the barButtonItem in the hierarchy, hoping it would grey it out, but the button is still green, you just can't press it. I made the button grey on the storyboard, then call this function, but the text ends up changing to white instead of the green color. I tried explicitly defining the color as I set it, but I get the same result. I do not want my back button to turn this green color, only the next button when it becomes available to press.
Any ideas what I'm doing wrong?

How can I show a back arrow in the master-view popover button for UISplitViewController in iOS 7?

In my detail VC, I am implementing this UISplitViewController delegate method:
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
It is then easy for me to set the title of the button, but the result is just a button with plain text, and no back arrow. I am looking to get something like the Mail app where the master popover button also has the back chevron.
How can I do this?
Create your custom bar button item, with the chevron image, set up as you want, and set the target and action of your bar button item to be that of the one passed by the delegate callback. This way, your bar button will perform the same action as the one the system passes to you. You must create your own bar button with an image, because there is no possible way with AppStore approved API to create back bar buttons.
In iOS7, the private subclasses are UINavigationItemView + _UINavigationBarBackIndicatorView. One is the button, the other - the chevron. _UINavigationBarBackIndicatorView is a subclass of UIImageView. So it's pretty close to what you will achieve.
In iOS 8, UISplitViewController has a method:
- (UIBarButtonItem *)displayModeButtonItem
If you set the returned bar button item as the left button of a navigation bar (UINavigationBar), it will display the chevron for you.
On the other hand, if you put the returned bar button item into a toolbar (UIToolbar), it will not display the chevron.
For places where I want the chevron back button shown, but also need several of my own bar button items shown (like the Mail app on iPad does), I have to use a UINavigationBar and a UIToolbar. It's an ugly solution, but I have to partially overlay the UINavigationBar on top of the UIToolbar in order to get a back button chevron along with several of my own bar button items.
To access the default back button image used by Apple as what Leo said, the arrow is a class of type _UINavigationBarBackIndicatorView. Set this image to a back bar button and you are good to go.
Here follows the hack,
UIImage *imgViewBack ;
for (UIView *view in self.navigationController.navigationBar.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. This is not any of the private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
// Set the image from the Default BackBtn Imageview
UIImageView *imgView = (UIImageView *) view;
if(imgView){
imgViewBack = imgView.image ;
}
}
}
This is based on Ryan Henning's answer.
It's possible to show a back button representing the master view from the detail view controller. The UISplitview controller doesn't provide a native method for this, but it returns a bar button object which we can directly assign as navigation controller bar button. Its obvious that the detail view controller should be inside a navigation controller for this to work.
self.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;

iOS custom shape navigation bar

I want to developer app with a custom navigation bar like in the following images:
I think that i need to subclass UINavigationBar and add button to centre of nav bar, but i don't really know how to make navigation bar look like on image. Can you please give me advice what should i do, links to any kind of documentation would be awesome!
Similar questions about navBar that doesn't helped me:
ios back button in the bar
Use custom Navigation Bar in iOS
Custom Navigation Bar in iOS 5
rogcar
EDIT:
My idea is next: make custom navigation bar height little bigger than default size, and add background image with arrow in it and with some transparency on the edges.
If you want a button (you probably do want) you can achieve it completely by subclassing UINavigationBar. You should remember that height of UINavigationBar is read-only property.
Style but not tappable:
So let's assume we subclass the navigation bar and add button there. You could do this and it will be going look great. For example:
- (void)drawRect:(CGRect)rect
{
self.backgroundColor = [UIColor lightGrayColor];
UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width/2-50, 0 , 100, 100)];
[myButton setBackgroundColor:[UIColor lightGrayColor]];
[myButton setTitle:#"Normal" forState:UIControlStateNormal];
[myButton setTitle:#"Highlighted" forState:UIControlStateHighlighted];
[self addSubview:myButton];
[self sendSubviewToBack:myButton];
}
But you will facing a problem that your button is non tapeable below UINvaigationBar. (I post an image on the bottom of the answer)
So there is clearly not a path you want to follow. Don't even try that.
Style but not tappable 2:
You may override this method in your navigation bar subclass
- (CGSize) sizeThatFits:(CGSize)size {
return CGSizeMake(custom_width, custom_height);
}
And then mask it using UIBezierPath for example
The right (tappable) way:
You have to create a view stick to your UINavigationBar. What i will do here (if you want it to every screen) is:
Make a Category of UIViewController which can draw (for example - this is easiest way) UIButton.
Style this 'UIButton' whatever you want (if you want
Pin action to 'UIButton': [btn addTarget:self action:#selector(menuShow:) forControlEvents:UIControlEventTouchUpInside];
menuShow: method should be declare in your category
You can call drawing button every time you want to redraw view controller.
As you can see there there will be two separates View: UINavigationBar and UIButton. This is allow you to set content under this little button and make it tapable.
So why just don't hide navigation bar, and use different view? Because iOS7 ;) When Apple change it in iOS7 for example then you have to rebuild your pseudo NavigationBar, with only additional view, you don't need to do anything.
You do not need to subclass UINavigationBar. Create UIView add to it UIImageView as background with image in the shape you need, add button.
Subclass UINavigationController hide UINavigationBar, add custom navigation bar.
First Hide navigation bar using -
self.navigationController.navigationBarHidden = YES;
Then create UIView with required height,height of navigationBar is 44px.Then create background image view, object of required UIButton and add all objects on created UIView as a subview.It will look like navigationBar.Thank you.
You can add your custom shaped view as titleView on the navigation bar.
Just make sure that clipsToBounds is set to NO, so it doesn't get clipped.

iOS7 Side menu status bar color transition. As in the iOS7 Facebook App

The iOS7 Facebook App has a right side menu that can be shown by swiping right to left or clicking on the upper right button. When this menu is opened the there is a color transition in the entire status bar from blue to black and vice-versa when closed.
This image shows both status bar side-to-side
This looks like a very good solution for iOS Apps with side menus.
Any ideas or ways about how to accomplish this?
I am currently using JASidePanels.
Thanks!
I managed to find a very simple, elegant way to do this, that mimics the Facebook app functionality perfectly.
Here's my approach:
Create view with status bar frame
Set view background color to black, opacity to 0
Add view as subview to any root view (you need a view that will cover both the center view and the menus, so that it won't be confined to any single view - a good option for this is the container view controller used by your menu controller implementation)
Set view's opacity in your menu controller implementation's menu animation method
Here's my specific implementation, using MMDrawerController:
I subclassed MMDrawerController (I actually already had a subclass for using MMDrawerController with storyboards), and added this code to the class's init method:
// Setup view behind status bar for fading during menu drawer animations
if (OSVersionIsAtLeastiOS7()) {
self.statusBarView = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
[self.statusBarView setBackgroundColor:[UIColor blackColor]];
[self.statusBarView setAlpha:0.0];
[self.view addSubview:self.statusBarView];
}
// Setup drawer animations
__weak __typeof(&*self) weakSelf = self; // Capture self weakly
[self setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
MMDrawerControllerDrawerVisualStateBlock block;
block = (drawerSide == MMDrawerSideLeft) ? [MMDrawerVisualState parallaxVisualStateBlockWithParallaxFactor:15.0] : nil; // Right side animation : Left side animation
if(block){
block(drawerController, drawerSide, percentVisible);
}
[weakSelf.statusBarView setAlpha:percentVisible]; // THIS IS THE RELEVANT CODE
}];
I also added self.statusBarView as a private property.
The first section of code creates a view, configures it, and adds it as a subview of the MMDrawerController subclass's view. The OSVersionIsAtLeastiOS7() method is a custom method that simplifies the check to see if the device is running iOS 7 (if it isn't, your custom view will show up below the status bar, which you don't want).
The second section of code is MMDrawerController's setDrawerVisualStateBlock method, which sets the animations code to be performed when a menu is being opened and closed. The first few lines of code are boilerplate code that sets one of the prebuilt animations blocks to each menu (I wanted parallax on the left, but nothing on the right). The relevant code is the last line of the block: [weakSelf.statusBarView setAlpha:percentVisible];, which sets the status bar view's opacity to match the percentage that the menu is currently open. This allows for the smooth cross animation you see in the Facebook app. You'll also notice I've assigned self to a variable weakSelf, so as to avoid the "retain cycle" compiler warning.
This is my specific approach using MMDrawerController and a subclass, which I did more for convenience because I already had the subclass in place, than because it is necessarily the best approach or the only way to do it. It could probably be implemented in several other ways, using MMDrawerController without a subclass, or using any other side-drawer menu implementation.
The ending result is a smooth fading to black animation behind the status bar, exactly as you see in the new Facebook app.
I've been trying to accomplish the same thing. The method I am using to do this is based on the following concepts:
A background image with a height of 64 points will fill both the
UINavigationBar and the UIStatusBar.
A background image with a height of 44 points will fill the UINavigationBar and leave the
UIStatusBar black.
You can add an subview to the top of the current navigationController's view and it will sit underneath the UIStatusBar.
So, first, you need to create two images with your desired UINavigationBar look:
A 640x128px image to cover navigation bar and status bar (ImageA)
And a 640x88px image to cover the navigation bar but leave the status bar black (ImageB).
In the application:didFinishLaunchingWithOptions: method, set the background of your UINavigationBar with ImageA with [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"ImageA.png"] forBarMetrics:UIBarMetricsDefault];
When the side menu starts to open, you are going to want switch the UINavigationBar so it uses ImageB and create a view which you will add underneath the UIStatusBar. Here is some sample code for doing just that:
// Add a property for your "temporary status bar" view
#property (nonatomic, strong) UIView *temporaryStatusBar;
And in the code where the side menu starts to open:
// Create a temporary status bar overlay
self.temporaryStatusBar = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
self.temporaryStatusBar.backgroundColor = [UIColor yourColor];
[self.navigationController.view addSubview:self.temporaryStatusBar];
// Update both the current display of the navigationBar and the default appearance values
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"imageB.png"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"imageB.png"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setNeedsDisplay];
As the side menu animates open, or as the user pans the menu, all you need to do then is adjust the alpha level of the UIStatusBar overlay. When the side menu is fully open, the UINavigationBar should have ImageB as its background image and the UIStatusBar overlay should have an alpha of 0. When the side menu closes, you'll want to replace the UINavigationBar background with ImageA and remove the UIStatusBar overlay.
Let me know if this works for you!
You can use this awesome slide menu library
https://github.com/arturdev/AMSlideMenu
In this demo project you can see how to do that by writing 4 lines of code.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Setting navigation's bar tint color
self.navigationController.navigationBar.barTintColor = [UIColor colorWithHex:#"#365491" alpha:1];
// Making view with same color that navigation bar
UIView *statusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
statusBarView.backgroundColor = [UIColor colorWithHex:#"#365491" alpha:1];
// Replace status bar view with created view and do magic :)
[[self mainSlideMenu] fixStatusBarWithView:statusBarView];
}

Cannot get UISearchBar Scope Bar to appear in Toolbar (or anywhere) on iPad

This is really causing me fits. I see a lot of info on putting a UISearchBar in the top row of a UITableView -- but I am putting the UISearchBar into the Toolbar at the top of my screen (on the iPad). I cannot find ANYTHING regarding how to handle UISearchBar and UISearchDisplayController using a UIPopoverController on the iPad. Any more info about the UISearchDisplayController using a UIPopoverController would be greatly appreciated. Please help with this as I am at my wit's end.
Using IB, I put a toolbar on the IUView on the iPad. I added the following: Search Bar (not Search Bar and Search Display) to the toolbar. I set the options to be as follows: Show Cancel Button, Show Scope Bar, Scope Button Titles are: "Title1" and "Title2" (with Title2's radio button selected). Opaque, Clear Context and Auto Resize are checked. I hooked up the delegate of Search Bar to the "File's Owner" and linked it to IBOutlet theSearchBar.
In my viewWillAppear I have the following:
//Just in case:
[theSearchBar setScopeButtonTitles:[NSArray arrayWithObjects:#"Near Me",#"Everywhere",nil]];
//Just in case (again):
[theSearchBar setShowsScopeBar:YES];
//doesn't seem to do anything:
//[theSearchBar sizeToFit];
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:theSearchBar contentsController:self];
[self setSearchDisplayController:searchDisplayController];
[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
//again--does not seem to do anything..but people have suggested it:
[theSearchBar sizeToFit];
Okay, so far, I thought, so good. So, I made the File's Owner .m file to be a delegate for: UISearchBarDelegate, UISearchDisplayDelegate.
My issue: I have yet to implement the delegates necessary to do the search but still... shouldn't I be seeing the scopeBar next to the search field when I click into the search field? Just so you know I DO see the log of the characters I type, so the delegate is working.
Here is a routine I used to check to see if IB really put the Scope Bar (UISegementedControl) in the searchbar:
for (UIView *v in theSearchBar.subviews)
{
if ([v isMemberOfClass:[UISegmentedControl class]])
{
// You've got the segmented control!
UISegmentedControl *scope = (UISegmentedControl *)v;
// Do your thing here...
NSLog(#"Found Scope: '%#'\n",scope);
NSLog(#"Scope Segments: '%d'\n",[v numberOfSegments]);
}
}
This shows:
[30013:207] Found Scope: '<UISegmentedControl: 0x68a06b0; frame = (0 0; 200 44); opaque = NO; layer = <CALayer: 0x68a0600>>'
[30013:207] Scope Segments: '2'
So, I know the 2 segments are there. I also know they are not showing up...
What am i doing wrong?
Why doesn't the Scope Bar appear? A results UIPopoverController appears with the title "Results" and "No results found" (of course) when i type the first character in my search...but no scope bar. (not that i expect anything other than "No Results Found".
I am wondering where the scope bar is supposed to appear...in the titleView of the UIPopover? In the toolbar to the right of the search area? Where?
[self.searchDisplayController searchBar] setScopeButtonTitles:[NSArray arrayWithObjects:#"Near Me",#"Everywhere",nil]];
This Might Help.
UISearchBar does not display it's scope when embedded in a UIToolbar, this is true even in iOS 7.
You must build your own UISegment and add it into the table view of the search results or build your own view to hold the UISearchBar that would display scope.

Resources