change UISearchBar text field background image for iOS-7 - ios7

I am specifically looking for an iOS-7 answer. If I had an image, the answer would be
[mySearchBar setSearchFieldBackgroundImage:myImage forState:UIControlStateNormal];
But I just want to apply a color. Is there a simple way of doing this with just a color? Again, for iOS-7.
Note: I see a host of very complicated answers here on SO: with traversing, etc. I hoping for something simple and that won't cause my app to be rejected.

If I understand correctly, you are looking for the barTintColor property. You can set the barTintColor property as such,
mySearchBar.barTintColor = [UIColor blackColor];
or
[mySearchBar setBarTintColor:[UIColor blackColor];
Hope that helps!

First you need to find the UITextField inside the search bar and then change its color. Here is the code to get the text field:
for (UIView *subView in searchBar.subviews)
{
for (UIView *secondLevelSubview in subView.subviews){
if ([secondLevelSubview isKindOfClass:[UITextField class]])
{
UITextField *searchBarTextField = (UITextField *)secondLevelSubview;
return searchBarTextField;
}
}
}
return nil;

Related

Objective C > UITableViewCell button not depressing

I have the following button being created in the cellForRowAtIndexPath section for this tableView:
UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
sched_button_a1.frame = CGRectMake(0, 0, 110, 52);
CGRect frame_a1 = sched_button_a1.frame;
// Resize height based on length of appointment
frame_a1.size.height = heightCalc;
sched_button_a1.frame = frame_a1;
[sched_button_a1 addTarget:self action:#selector(showAppointment:) forControlEvents:UIControlEventTouchUpInside];
[sched_button_a1 setTitle:[NSString stringWithFormat:#"APPT: %#", APPT_ID ] forState:UIControlStateNormal];
sched_button_a1.layer.backgroundColor = [UIColor redColor].CGColor;
[sched_a1 addSubview:sched_button_a1];
As you can see it's calling showAppointment which is presently just:
-(void)showAppointment:(UIButton*)sender {
NSLog(#"Button pushed");
}
showAppointment is also defined here:
-(void)showAppointment:(UIButton*)sender;
The button shows up fine and gets the correct text and background and appears to be in the foreground, however, when I click on it nothing happens and it doesn't look like the button even gets depressed.
What am I doing wrong or missing?
Edit: I have gone back and removed the sched_a1 view so that the button is directly created in the contentView and this had no effect. It still appears that the only gesture being recognized is the one used to scroll the table. Tapping the button does not appear to change the color of the text or otherwise indicate that the button has been pressed and no log entry is created.
Edit 2: Added cellForRowAtIndexPath to paste bin
http://pastebin.com/WXezfW96
I had a similar issue recently, which I struggled to understand. The solution I came up with was to set the bounds of the button as well and also check for UIControlEventTouchDown rather than UIControlEventTouchUpInside.
Have you tried using cancelsTouchesInView? If you added tap gesture, I think the tap gesture or the tap in table cell overrides the touches in your button. Try using this code:
UIGestureRecognizer *tap= [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(yourAction)];
tap.cancelsTouchesInView = NO;
tap.delegate = self;
[yourButton addGestureRecognizer:tap];
But don't forget to add <UIGestureRecognizerDelegate> in your .h file
But I agree on Mike. Make it short and simple when creating table cell. I think you can use custom cell subclass and xib file.
I'm also new to objective C so if I say something wrong I'm sorry, I'm just trying to help.
UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
in this change UIButtonTypeCustom to UIButtonTypeRoundedRect
Scott, you may want to try my famous troubleshooting technique:
Determine whether the button or the action is the root cause:
UIImage *image = [UIImage imageNamed:#"image.png"];
[button setBackgroundImage:image forState:UIControlStateHighlighted|UIControlStateSelected]
Instead of:
-(void)showAppointment:(UIButton*)sender {
try
-(void)showAppointment:(id*)sender {
Use breakpoints.
If none of the above works consider refactoring your code that looks a bit messy.
Hey i have checked the code you wrote, it is working fine. Can you check if you have written similar to the code below in your cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Identifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier];
}
UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
sched_button_a1.frame = CGRectMake(0, 0, 110, 52);
CGRect frame_a1 = sched_button_a1.frame;
[sched_button_a1 addTarget:self action:#selector(showAppointment:) forControlEvents:UIControlEventTouchUpInside];
[sched_button_a1 setTitle:#"Your Text" forState:UIControlStateNormal];
sched_button_a1.layer.backgroundColor = [UIColor redColor].CGColor;
[cell.contentView addSubview:sched_button_a1];
return cell;
}
I was not able to debug further as you have not kept your entire cellForRowAtIndexPath code. Hope this could help you to solve your problem
Since you are using a button type of UIButtonTypeCustom, you will need to set the attributes for UIControlStateHighlighted and UIControlStateSelected so that you achieve the effect you want for appearing to press the button.
You can change the title color or the background image for the highlighted and selected states using one of the following UIButton methods:
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state
As an additional note regarding the code in the cellForRowAtIndexPath, you shouldn't be getting the data from sql in the method it would be destructive to your table view performance, get all the data you need before and have them stored in object in an array and then in the cellForRowAtIndexPath method you would just update the values labels from the object for the row.

Weird behaviour of UIButton with tintColor on enabled/disabled states

UPDATE:
Even UIBarButtonItems do not respond to state change, visually.
The scenario:
I have a UIButton of type UIButtonTypeSystem initialized as below:
sendButton = [UIButton buttonWithType:UIButtonTypeSystem];
sendButton.backgroundColor = [UIColor clearColor];
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
sendButton.opaque = YES;
sendButton.clearsContextBeforeDrawing = NO;
sendButton.frame = CGRectMake(275, 6, 50, 35);
UIImage* sendImage = [UIImage imageNamed:#"toilet_paper"];
[sendButton setImage:[UIImage imageWithCGImage:sendImage.CGImage scale:sendImage.scale orientation:UIImageOrientationLeft]
forState:UIControlStateNormal];
sendButton.enabled = NO;
[sendButton addTarget:self action:#selector(post) forControlEvents:UIControlEventTouchUpInside];
The Purpose:
It is associated with a UITextView such that it is set to enabled if there is some text in the textView AND my host is available (checked through Reachability) and it's enabled property is changed in textViewDidChange: delegate method with the following:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
According to this enabled state, the button must toggle between SEND_BUTTON_COLOR (enabled = YES) and grayColor (enabled = NO).
The Problem:
Up until now, the code used to work fine. It was gray when there was no text in the textView and it became SEND_BUTTON_COLOR as soon as there was some text in the textView. However, out of the blue, it has stopped this behaviour. What happens is, it stays gray all the time irrespective of the content of the textView. Once it is pressed, it becomes SEND_BUTTON_COLOR and stays that way, again irrespective of the textView text.
How do I regain the behaviour of the button I used to have on my UIButton?
You have to set your button's tint color again in the textViewDidChange delegate method.
In your delegate where you are setting the enabled state:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
if(sendButton.enabled){
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
}
else{
//Set Another Color For Disabled State
}
As it appears, the problem was on my part. I had subclassed UIButton in the .m file of a different VC (not imported by the VC in question, or any other VCs it had imported):
#implementation UIButton (Border)
- (void) setEnabled:(BOOL)enabled {
if (enabled) {
self.layer.borderColor = UIColorFromRGB(0x888888).CGColor;
} else {
self.layer.borderColor = UIColorFromRGB(0xdddddd).CGColor;
}
[super setEnabled:enabled];
[self setNeedsDisplay];
}
#end
Somehow, this interfered with my button. After weeks of further subclassing, changing images, changing titles, etc, I was able to diagnose the issue (accidentally) by jumping to definition (CMD + Click) of the enabled method, and it took me straight to the source of the issue (the subclass code). Commented it out, and voila. Things were back to normal.
I hope this helps someone in the future who faces the same issue (or makes the same mistake I did).

UISearchBar text color change in iOS 7

How to change text color of UISearchBar in iOS 7?
In iOS 6, I was subclassing the UISearchBar and in layoutSubviews customising the properties of UITextField subview of UISearchBar.
But in iOS 7, UISearchBar doesn't have UITextField as its subview. How to fix this?
In iOS 7 to access Text Field you have to reiterate on level more. Change your code like this
for (UIView *subView in self.searchBar.subviews)
{
for (UIView *secondLevelSubview in subView.subviews){
if ([secondLevelSubview isKindOfClass:[UITextField class]])
{
UITextField *searchBarTextField = (UITextField *)secondLevelSubview;
//set font color here
searchBarTextField.textColor = [UIColor blackColor];
break;
}
}
}
Note : This is Not Public API
OR
You can use appearance Property of UIControls, Like
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
Note: Appearance proxy can be used for iOS 9.0+
OutPut
You can set The tintcolor to apply to key elements in the search bar.
Use tintColor to tint foreground elements.
Use barTintColor to tint the bar background.
In iOS v7.0, all subclasses of UIView derive their behavior for tintColor from the base class. See the discussion of tintColor at the UIView level for more information.
Apple Doc
You can set the text colour by
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor blueColor]];
For XCode 6 (iOS8 SDK) the following DOESN'T work
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor redColor]];
But the following DOES work (for deployment to iOS7 and iOS8)
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
While it's true that the UIAppearance protocol is a "public API," it's not true that UITextField supports this.
If you take a look at UITextField.h and look for the string "UI_APPEARANCE_SELECTOR" you'll see that it has no instances of this string. If you look at UIButton, you find quite a few - these are all of the properties that are officially supported by the UIAppearance API. It's somewhat well-known that UITextField is not supported by the UIAppearance API, so the code in Sandeep's answer will not always work and it's actually not the best approach.
This is a useful post with useful links: http://forums.xamarin.com/discussion/175/uitextfield-appearance
The correct approach is unfortunately messy - iterate through the subviews (or subviews of main subview for iOS7) and set it manually. Otherwise you will have unreliable results. But you can just create a category for UISearchBar and add a setTextColor:(UIColor*)color method. Example:
- (void)setTextColor:(UIColor*)color
{
for (UIView *v in self.subviews)
{
if([Environment isVersion7OrHigher]) //checks UIDevice#systemVersion
{
for(id subview in v.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
((UITextField *)subview).textColor = color;
}
}
}
else
{
if ([v isKindOfClass:[UITextField class]])
{
((UITextField *)v).textColor = color;
}
}
}
}
Caution : This should lead to App Rejection!
KVC FTW. This did it for me.
UITextField *searchField = [self.searchBar valueForKey:#"_searchField"];
searchField.textColor = [UIColor redColor];
You can set the text attributes like so
[[UITextField appearanceWhenContainedIn:[<YOUR_CONTROLLER_NAME> class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont systemFontOfSize:14.0]}];
Here is working example done in C# using Xamarin:
SearchBar = new UISearchBar ();
foreach (var subView in SearchBar.Subviews) {
foreach (var field in subView.Subviews) {
if (field is UITextField) {
UITextField textField = (UITextField)field;
textField.TextColor = UIColor.White;
}
}
}
Hope this helps someone.
This seems to be the correct answer https://stackoverflow.com/a/19315895/2493073
The Swift version of it is:
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).textColor = UIColor.blueColor()
This would only work for iOS 9.0, in order to make it work for lower versions you'll need to follow this question. https://stackoverflow.com/a/27807417/2493073
Swift Extension
public extension UISearchBar {
public func setTextColor(color: UIColor) {
let svs = subviews.flatMap { $0.subviews }
guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
tf.textColor = color
}
}
In my case, I have multiple UISearchBar objects and they need to change the textField font color. The appearanceWhenContainedIn update one UISearchBar behavior, but another doesn't.
I subclass the UISearchBar and implement custom -(id)initWithFrame: as following, and it works.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.searchBarStyle = UISearchBarStyleMinimal;
self.tintColor = [UIColor whiteColor];
self.barTintColor = [UIColor whiteColor];
[[UITextField appearanceForTraitCollection:self.traitCollection whenContainedIn:[self class], nil] setDefaultTextAttributes:
#{
NSForegroundColorAttributeName : [UIColor whiteColor]
}];
}
return self;
}
UIAppearance Protocol Reference said that,
In other words, the containment statement in
appearanceWhenContainedIn: is treated as a partial ordering. Given a
concrete ordering (actual subview hierarchy), UIKit selects the
partial ordering that is the first unique match when reading the
actual hierarchy from the window down.
So, appearanceWhenContainedIn: won't deal with all UISearchBar in the hierachy of UIWindow. And it suggests that.
Use the appearanceForTraitCollection: and
appearanceForTraitCollection:whenContainedIn: methods to retrieve the
proxy for a class with the specified trait collection.
The easiest way to do it is by putting this code in viewDidAppear or viewWillAppear:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
This works in iOS 8 and Xcode 6, unlike some of the other code. It can mess around with the font and text size, etc, but you can change that in the text attributes.
That changes the text colour for all search bars in your app. If you only want to change one, use the above code, and then in any other views with a search bar, use the same code but set the colour to whatever you want.
you can use search bar inside textfield
UISearchBar * searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 50, 320, 44) ];
searchBar.autocorrectionType = UITextAutocapitalizationTypeWords;
searchBar.delegate = self;
searchBar.searchBarStyle = UISearchBarStyleMinimal;
searchBar.barTintColor = [UIColor redColor];
[[UITextField appearanceWhenContainedIn:[searchBar class], nil]setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
[self.view addSubview:searchBar];
Update in Swift 3
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = UIColor.black
Even though I would have preferred to use appearance API, it didn't work with iOS8. Here's the least hackish solution I did come with:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.shouldEnableSearchBar)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
UITextField *searchBarTextField = [[AFPBaseViewController findSubviewsOfView:self.searchBar ofClass:[UITextField class]] firstObject];
searchBarTextField.textColor = AFPConstantsColorGold;
});
}
}
You could maybe even create a UIView category with this. The reason why this has to be called in viewDidAppear is that UISearchBar is actually contained in a ViewController, and doesn't load all its subviews until it has appeared on screen. It could be added into viewWillAppear too, but I haven't tested it.
+ (NSArray *)findSubviewsOfView:(UIView *)view ofClass:(Class)class
{
NSMutableArray *targetSubviews = [NSMutableArray new];
for (id subview in view.subviews)
{
if ([subview isKindOfClass:class])
{
[targetSubviews addObject:subview];
}
if ([subview subviews].count)
{
[targetSubviews addObjectsFromArray:[self findSubviewsOfView:subview ofClass:class]];
}
}
return targetSubviews.copy;
}
This is the right solution for iOS8:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:14], NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
You have to set the font as well, otherwise, the font size will be wrong.
This class will give you full control over every item in the UISearchBar
import UIKit
class SMTSearchBar: UISearchBar {
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
initialize()
}
convenience init() {
self.init(frame: CGRectZero)
initialize()
}
// Style the view
func initialize() {
// Search Area
let searchField = valueForKey("searchField") as! UITextField
searchField.textColor = Colors.White
searchField.font = UIFont(name: Fonts.MuseoSans500, size: 16)
searchField.backgroundColor = Colors.Black.colorWithAlphaComponent(0.1)
// Icons
let searchIcon = UIImage(named: Icons.Search)?.imageWithTint(Colors.White)
let smallClearIconNormal = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White)
let smallClearIconHighLight = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White.colorWithAlphaComponent(0.5))
setImage(searchIcon, forSearchBarIcon: .Search, state: .Normal)
setImage(smallClearIconHighLight, forSearchBarIcon: .Clear, state: .Highlighted)
setImage(smallClearIconNormal, forSearchBarIcon: .Clear, state: .Normal)
}
func setPlaceHolder(placeholder: String) {
for subView in subviews{
for subsubView in subView.subviews {
if let textField = subsubView as? UITextField {
textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName: Colors.White.colorWithAlphaComponent(0.5)])
}
}
}
}
}
Usage (in navigation bar)
let searchBar:SMTSearchBar = SMTSearchBar()
searchBar.sizeToFit()
searchBar.setPlaceHolder("Search for cool things")
navigationItem.titleView = searchBar
searchBar.becomeFirstResponder()

Can't change the size of UISearchbar's text field

I have a UISearchBar created in InterfaceBuilder and IBOutlet of it called userSearchBar. Now I want to change its width and height in code and can't do it. Here is my code:
for (UIView * const subview in userSearchBar.subviews) {
if ([subview isKindOfClass: NSClassFromString(#"UISearchBarBackground")]) {
[subview removeFromSuperview];
}
if ([subview isKindOfClass: [UITextField class]]) {
UITextField * const textField = (UITextField *)subview;
textField.textColor = [UIColor redColor];
textField.text = #"Enter text";
textField.frame = CGRectMake(0, 0, 250, 50);
}
}
All other changes (text, color, removing bar) works perfectly but changing the size not.
I've come up against exactly this myself, and I found the best way through was to write my own search bar from scratch, subclassing UIView. This gives me legitimate access to all the properties I might want to customise (such as background, colour when considering design or brand), rather than trying hack through like this. It's future proof, not that hard, and not hugely time consuming. It's a fun exercise and will deliver exactly what you want.

Adding a row with transparent background

I have an NSTableView, with an "add" button below it. When I click on the button, a new row gets added to the table and is ready for user input.
The row appears in a white color. Can I set the color of the row to a transparent color? Is this possible? I cannot figure out how to do this.
My code for setting my table to be transparent:
[myTable setBackgroundColor:[NSColor clearColor]];
[[myTable enclosingScrollView] setDrawsBackground: NO];
Code for adding a row:
[myTableArray addObject:#""];
[myTable reloadData];
[myTable editColumn:0 row:[myTableArray count]-1 withEvent:nil select:YES];
try setting the cell's background color transparent
[cell setBackgroundColor:[UIColor clearColor]];
it works for me
I think you may have to do some subclassing to accomplish what you're trying to do.
By subclassing your NSTableView you can override the preparedCellAtColumn:row: method like so:
- (NSCell*) preparedCellAtColumn:(NSInteger)column row:(NSInteger)row {
NSTextFieldCell *edit_field;
edit_field = (NSTextFieldCell*) [super preparedCellAtColumn:column row:row];
if ( [self editedRow] == row && [self editedColumn] == column ) {
[edit_field setBackgroundColor:[NSColor clearColor]];
[edit_field setDrawsBackground:NO];
}
return edit_field;
}
However, the NSTableView documentation indicates that your cell has another method called, which seems to reset the color. (editWithFrame:inView:editor:delegate:event:) Creating a subclass of NSTextViewCell that overrides this method may do what you're looking for.
EDIT
Searching through the documentation I found this:
If the receiver isn’t a text-type NSCell object, no editing is performed. Otherwise, the field editor (textObj) is sized to aRect and its superview is set to controlView, so it exactly covers the receiver.
So what you need to customize in this case is the field editor, which is covering up any display changes you're performing on the NSTableView or the cell.
The field editor is returned by the window delegate's method windowWillReturnFieldEditor:toObject:
This should let you set the properties of the edited cell before returning it to the NSTableView
EDIT
Tried this to no avail but might help out:
-(id) windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client{
NSText *editor = [window fieldEditor:YES forObject:client];
[editor setBackgroundColor:[NSColor clearColor]];
[editor setDrawsBackground:NO];
return [editor autorelease];
}