25

How can I change the font size and font style of UISearchBar in iOS 7?

UITextField *textField = [[searchBar subviews] objectAtIndex:1];
[textField setFont:[UIFont fontWithName:@"Helvetica" size:20]];

Working in iOS 6 but it's getting crash in iOS 7

rmaddy
  • 314,917
  • 42
  • 532
  • 579
SWT
  • 531
  • 2
  • 5
  • 16
  • 1
    What is the error? And never dig into the private subview structure of a standard UI component. That stuff changes and makes your code break. Use provided APIs to do this stuff. – rmaddy Oct 03 '13 at 14:17
  • Please check this: http://stackoverflow.com/questions/19048766/uisearchbar-text-color-change-in-ios-7 I think what you try to achieve is the same. – o15a3d4l11s2 Oct 03 '13 at 14:19
  • @rmaddy is correct and detailed explanation of **safe approach** is given in my [Answer](http://stackoverflow.com/a/19161701/1603072). – Bhavin Oct 04 '13 at 06:53

9 Answers9

67

Try this, It's Working Fine for iOS 5.0 and up: (iOS 7 also)

- (void)viewDidLoad
{

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setFont:[UIFont fontWithName:@"Helvetica" size:20]];

}

For iOS 8

- (void)viewDidLoad
    {

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{
            NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:20],
      }];

    }
Siva
  • 1,848
  • 2
  • 23
  • 40
  • 3
    I have small query on this. I have implemented the same and it is working.But if I navigate to some view controller and back to the same screen the font is changing to default.Any Idea? – Ganesh Jul 18 '14 at 11:58
  • 1
    Same thing here on iOS 8. Works fine the first time. But when I navigate to another screen and back, the font is back to the system default. – Mike Sep 13 '14 at 01:20
  • https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISearchBar_Class/ UISearchBar has no hierarchy from textfield. – jeet.chanchawat Dec 10 '15 at 06:17
  • @jeet.chanchawat – that does not matter. The appearance is defined for UITextFields that are subviews of UISearchBar, and there is one in there. – Adam Kaplan Mar 11 '16 at 18:46
  • 'appearanceWhenContainedIn:' is deprecated: first deprecated in iOS 9.0 - Use +appearanceWhenContainedInInstancesOfClasses: instead [[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setDefaultTextAttributes:@{ NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:20] }]; – Sathe_Nagaraja Feb 10 '18 at 16:03
  • `let appearence = UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self])` This doesn't work: `appearence.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.heavy)` But this works fine: `appearence.defaultTextAttributes = [NSAttributedStringKey.font.rawValue: UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.heavy)]` – Konstantin Berkov Sep 10 '18 at 13:26
34

The accepted answer did not work for me on iOS 7.1. I had to change it to this:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{
            NSFontAttributeName: [UIFont fontWithName:@"Avenir-Heavy" size:20.],
}];
joel.d
  • 1,611
  • 16
  • 21
  • 3
    This way overcomes the issue [tried on iOS 8.0] mentioned in Ganesh's comment (that by only using the setFont and not setDefaultTextAttribute the text is only changed on the first view and not after navigating from and back to the screen in questions). – Mike Sep 13 '14 at 01:38
  • this answer is better. – Harshit Gupta Nov 03 '14 at 17:40
  • Yup, this was the only method which would work each time for me, on iOS 8.1. – Mike Gledhill Feb 06 '15 at 10:27
6

iOS 10 Swift 3:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSFontAttributeName:UIFont(name: "Avenir-Heavy", size: 22)!]
Piotr Tomasik
  • 9,074
  • 4
  • 44
  • 57
2

appearanceWhenContainedIn: is deprecated in iOS9, use the following:

[[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setDefaultTextAttributes:@{ NSFontAttributeName: [UIFont fontWithName:@"FontName" size:14]}];
Filip
  • 33
  • 6
1

As rmaddy said, you should not rely on the private subview structure of a standard UI component. That stuff changes and makes your code break. You should use provided APIs to do this stuff.

I think much safe approach is :

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setFont:[UIFont systemFontOfSize:14]];

or you can also use this sample code :

for(UIView *subView in searchBar.subviews) {
    if ([subView isKindOfClass:[UITextField class]]) {
        UITextField *searchField = (UITextField *)subView;
        searchField.font = [UIFont systemFontOfSize:14];
    }
}

The above code is also safer (at least compared to the one mentioned in the Question) as it's not using the index of subviews.

Bhavin
  • 27,155
  • 11
  • 55
  • 94
  • The second approach here doesn't appear to be that safe. You're still relying on the subview structure, as you're assuming that a UISearchBar has a UITextField as as direct subview. Just because you're avoiding an index doesn't mean you're avoiding the private subview structure. – rickerbh Feb 24 '14 at 06:02
  • @rickerbh: Yeah, true. Actually, even I believe that OP should use the first approach that I mentioned in my Answer. – Bhavin Feb 24 '14 at 06:12
1

For those looking for a working Swift version, I've adapted this answer. Swift doesn't currently support Objc varargs methods, so it doesn't work directly with the above methods. We can work around this by making an objective-c category that doesn't use varargs and calls what we need:

// UIAppearance+Swift.h
@interface UIView (UIViewAppearance_Swift)
// appearanceWhenContainedIn: is not available in Swift. This fixes that.
+ (instancetype)my_appearanceWhenContainedIn:(Class<UIAppearanceContainer>)containerClass;
@end

// UIAppearance+Swift.m
@implementation UIView (UIViewAppearance_Swift)
+ (instancetype)my_appearanceWhenContainedIn:(Class<UIAppearanceContainer>)containerClass {
    return [self appearanceWhenContainedIn:containerClass, nil];
}
@end

Just be sure to #import "UIAppearance+Swift.h" in your bridging header.

Then just call:

UITextField.my_appearanceWhenContainedIn(UISearchBar.self).font = UIFont.systemFontOfSize(14.0)
Community
  • 1
  • 1
Mike Sprague
  • 3,567
  • 1
  • 22
  • 25
1

For Swift 4 you need to reference the NSAttributedStringKey enum:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self])
        .defaultTextAttributes = [NSAttributedStringKey.font.rawValue: UIFont(...)]
Andrew
  • 1,279
  • 2
  • 13
  • 19
1

In Swift 5

code of @Piotr Tomasik still working in swift 5 after bit changes

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.font:UIFont(name: "poppins", size: 13)!]
Sanjay Mishra
  • 672
  • 7
  • 17
0
  • SWIFT
  • IOS 8

For me, this worked using a recursive function to find the actual textfield.

extension UIView {

func recursive_applyTheme_Search(
    #dynamicTextStyle: NSString,
    bgColor: UIColor,
    cursorColor: UIColor,
    textColor: UIColor,
    placeholderTextColor: UIColor,
    borderColor: UIColor,
    borderWidth: CGFloat,
    cornerRadius: CGFloat) {

    for subview in self.subviews
    {
        if subview is UITextField {

            (subview as! UITextField).applyThemeForSearchBar(
                dynamicTextStyle: dynamicTextStyle,
                bgColor: bgColor,
                cursorColor: cursorColor,
                textColor: textColor,
                placeholderTextColor: placeholderTextColor,
                borderColor: borderColor,
                borderWidth: borderWidth,
                cornerRadius: cornerRadius)
        }
        else { subview.recursive_applyTheme_Search(
                dynamicTextStyle: dynamicTextStyle,
                bgColor: bgColor,
                cursorColor: cursorColor,
                textColor: textColor,
                placeholderTextColor: placeholderTextColor,
                borderColor: borderColor,
                borderWidth: borderWidth,
                cornerRadius: cornerRadius) }
    }

}
}
Andrei Popa
  • 159
  • 9
  • Also, most of WWDC videos recommend that font should conform to Dynamic Type, use let font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) – Andrei Popa Apr 12 '15 at 09:41