I have my own subclass of UIButton. I add UIImageView on it and add an image. I would like to paint it over the image with a tint color but it doesn't work.
So far I have:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.clipsToBounds = YES;
self.circleView = [[UIView alloc]init];
self.circleView.backgroundColor = [UIColor whiteColor];
self.circleView.layer.borderColor = [[Color getGraySeparatorColor]CGColor];
self.circleView.layer.borderWidth = 1;
self.circleView.userInteractionEnabled = NO;
self.circleView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.circleView];
self.iconView = [[UIImageView alloc]init];
[self.iconView setContentMode:UIViewContentModeScaleAspectFit];
UIImage * image = [UIImage imageNamed:#"more"];
[image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.iconView.image = image;
self.iconView.translatesAutoresizingMaskIntoConstraints = NO;
[self.circleView addSubview:self.iconView];
...
and on selection :
- (void) setSelected:(BOOL)selected
{
if (selected) {
[self.iconView setTintColor:[UIColor redColor]];
[self.circleView setTintColor:[UIColor redColor]];
}
else{
[self.iconView setTintColor:[UIColor blueColor]];
[self.circleView setTintColor:[UIColor blueColor]];
}
}
What did I do wrong? (The color of the image always stays the same as it was originally.)
Instead of this code:
[image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
you should have:
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
Use this in Swift 4.1
image = UIImage(named: "name")!.withRenderingMode(.alwaysTemplate)
You can also just set this on your asset. Make sure your image contains all white pixels + transparent.
(Can't edit #Zhaolong Zhong post)
In swift 3.0, you can do:
let image = UIImage(named: "your_image_name")!.withRenderingMode(.alwaysTemplate)
yourImageView.image = image
yourImageView.tintColor = UIColor.blue
Swift version: 5.2
let tintableImage = UIImage(named: "myImage")?.withRenderingMode(.alwaysTemplate)
imageView.image = tintableImage
imageView.tintColor = UIColor.red
Objective C
self.imgView.image = [self.imgView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.imgView setTintColor:[UIColor darkGrayColor]];
Or
You can also just set this on your asset.
In swift 2.0+, you can do:
let image = UIImage(named: "your_image_name")!.imageWithRenderingMode(.AlwaysTemplate)
yourImageView.image = image
yourImageView.tintColor = UIColor.blueColor()
One step further. This is a drop-in subclass of UIImageView. (Not exact solution for original question.) Use in Interface Builder by setting class name to TintedImageView. Updates in real-time inside the designer as tint color changes.
(Swift 3.1, Xcode 8.3)
import UIKit
#IBDesignable class TintedImageView: UIImageView {
override func prepareForInterfaceBuilder() {
self.configure()
}
override func awakeFromNib() {
super.awakeFromNib()
self.configure()
}
#IBInspectable override var tintColor: UIColor! {
didSet {
self.configure()
}
}
private func configure() {
self.image = self.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
}
}
Make the imageView
let imageView = UIImageView(frame: frame!)
imageView.contentMode = .ScaleAspectFit
imageView.tintColor = tintColor
Make the image
let mainBundle = NSBundle.mainBundle()
var image = UIImage(named: filename!, inBundle: mainBundle, compatibleWithTraitCollection: nil)
image = image?.imageWithRenderingMode(.AlwaysTemplate)
Wire them together
imageView?.image = image
Display it
view.addSubview(imageView)
all said is correct. my contribution If You cannot / dont want to apply to every UiImageView, OR for efficiency You need to render ONCE (or example for cells of tableviews)
func tint(with color: UIColor) -> UIImage {
var image = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(origin: .zero, size: size))
image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
And set to all UI elements this UIImage.
#odemolliens answer should just work.
But if you are still having issues, make sure that the tint color you are applying to the UIImageView is different from the one defined in the Interface Builder.
Related
How can i put an UILabel over the thumb of UISlider...so that when i move the thumb....UILabel will also move....as it is on the thumb...
Any idea??
Try this
yourLabel = [[UILabel alloc]initWithFrame:....];
//Call this method on Slider value change event
-(void)sliderValueChanged{
CGRect trackRect = [self.slider trackRectForBounds:self.slider.bounds];
CGRect thumbRect = [self.slider thumbRectForBounds:self.slider.bounds
trackRect:trackRect
value:self.slider.value];
yourLabel.center = CGPointMake(thumbRect.origin.x + self.slider.frame.origin.x, self.slider.frame.origin.y - 20);
}
I could get most accurate value by using this snippet.
The "knob" isn't available per public API, so bad chances for hooking it up - if it is a subview at all and not just drawn directly.
So you should add you label to the same view as the slider (make sure you add it later so that appears over it). You can then listen for the value change events and place your label accordingly. It is linear scaling between the endpoints that you need to figure out at first, but it shouldn't be too difficult.
Edit with code:
yourLabel = [[UILabel alloc]initWithFrame:....];
// .. configure label
[[yourSlider superview] addSubview:yourLabel];
[yourSlider addTarget:self action:#selector(adjustLabelForSlider:) forControlEvents:UIControlEventValueChanged];
-(void)adjustLabelForSlider:(id)slider
{
float value = slider.value;
float min = slider.minimumValue;
float max = slider.maximumValue;
CGFloat newX = ...; // Calculate based on yourSlider.frame and value, min, and max
CGFloat newY = ...;
[yourLabel setCenter:CGPointMake(newX,newY)];
}
Note: untested code ;-)
Same answer with swift3:
let trackRect: CGRect = slider.trackRect(forBounds: slider.bounds)
let thumbRect: CGRect = slider.thumbRect(forBounds: slider.bounds , trackRect: trackRect, value: slider.value)
let x = thumbRect.origin.x + slider.frame.origin.x
let y = slider.frame.origin.y - 20
sliderLabel.center = CGPoint(x: x, y: y)
extension UIImage {
class func imageWithLabel(_ label: UILabel) -> UIImage {
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
defer { UIGraphicsEndImageContext() }
label.layer.render(in: UIGraphicsGetCurrentContext()!)
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
}
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate, UITextViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource, UIScrollViewDelegate
{
func maskRoundedImage(image: UIImage, radius: CGFloat) -> UIImage {
let imageView: UIImageView = UIImageView(image: image)
let layer = imageView.layer
layer.masksToBounds = true
layer.cornerRadius = radius
UIGraphicsBeginImageContext(imageView.bounds.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return roundedImage!
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 28, height: 28))
label.backgroundColor = .black
label.textAlignment = .center
label.font = label.font.withSize(12)
label.text = String(Int(round( backlightSlider.value * 100 )))
label.textColor = .white
var image = UIImage.imageWithLabel(label)
image = maskRoundedImage(image: image, radius: 14.0)
backlightSlider.setThumbImage(image, for: .normal)
}
Just add an imageview on the thumb of slider add a label on imageview
- (IBAction)valueChangedSlider:(id)sender {
handleView = [_slider.subviews lastObject];
label = [[UILabel alloc] initWithFrame:handleView.bounds];
label = (UILabel*)[handleView viewWithTag:1000];
if (label==nil) {
label = [[UILabel alloc] initWithFrame:handleView.bounds];
label.tag = 1000;
[label setFont:[UIFont systemFontOfSize:12]];
label.textColor = [UIColor redColor];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
[handleView addSubview:label];
}
label.text = [NSString stringWithFormat:#"%0.2f", self.slider.value];
}
If anybody is looking for answer in Swift, please take a look of my answer here:- Put Label over UISlider Thumb
It'll work like a charm :)
This could be very helpful...
How to get the center of the thumb image of UISlider
for subView in searchBar.subviews {
if let scopeBar = subView as? UISegmentedControl {
scopeBar.backgroundColor = UIColor.blueColor()
}
}
I've been trying the above code to attempt to get a reference to the scopeBar and subsequently set its background color, but I am not able to get a reference. It seems to only go through the loop once, implying that there is only a single subview for the search bar. In the debugger the search bar appears to have an instance variable called _scopeBar with a type of (UISegmentedControl *).
if let topView = searchBar.subviews.first {
for subView in topView.subviews {
if let cancelButton = subView as? UIButton {
cancelButton.tintColor = UIColor.whiteColor()
cancelButton.enabled = true
}
}
}
The second block of code works for accessing the cancelButton of the search bar.
You can set the scopeBar background image as a solid color image.
First, you will need to create an UIImage from a color. In order to do that, you can create a function, or an extension on the UIImage, such as the following code:
Swift 3
import UIKit
extension UIImage {
class func imageWithColor(color: UIColor) -> UIImage {
let rect: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1, height: 1), false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
After that, you can simply set the backgroundImage on the scope bar:
Swift 3
// Set the scopeBar's background color:
searchBar.scopeBarBackgroundImage = UIImage.imageWithColor(color: UIColor.blue)
I have a sample issue, and I solved this as below code.
CGSize imageSize = CGSizeMake(64, 64);
UIColor *fillColor = [UIColor colorWithRed:228/255.0 green:228/255.0 blue:228/255.0 alpha:1.0];
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[fillColor setFill];
CGContextFillRect(context, CGRectMake(0, 0, imageSize.width, imageSize.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.searchController.searchBar.scopeBarBackgroundImage = image;
- (void)changeScopeBarColor {
NSMutableArray<UIView*> *views = [NSMutableArray new];
NSArray<UIView *> *subviews = [_searchBar subviews];
[views addObjectsFromArray:subviews];
for (;;) {
if (views.count == 0) {
break;
}
UIView *v = [views firstObject];
[views removeObject:v];
if ([[[v class] description] isEqualToString:#"_UISearchBarScopeBarBackground"]) {
v.backgroundColor = [UIColor whiteColor];
break;
}
if (v.subviews.count > 0)
[views addObjectsFromArray:v.subviews];
}
}
I'm having trouble setting properly a custom back indicator image. The indicator is not centered!
Here is a pic:
I'm setting the indicator image in didFinishLaunchingWithOptions: method...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIImage *image = [UIImage imageNamed:#"Back"];
[UINavigationBar appearance].backIndicatorImage = image;
[UINavigationBar appearance].backIndicatorTransitionMaskImage = image;
return YES;
}
How can I center it?
p.s I've already read this Custom back indicator image in iOS 7 not vertically centered, but actually it didn't work for me.
UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 2, 0);
UIImage *backArrowImage = [[UIImage imageNamed:#"Back"] imageWithAlignmentRectInsets:insets];
[[UINavigationBar appearance] setBackIndicatorImage:backArrowImage];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:backArrowImage];
That happens because you are just changing the image source of the Back Indicator in your UINavigationView, and not the frame as well.
See, when the UINavigationView is created, the Back Indicator's frame is set to hold the size of the default iOS 7 back button image. The default back button image is bigger than yours, and that's why it looks not aligned.
To fix that you have to reset the Back Indicator's Frame to hold the size of your image. Another option is to create a UIButton with the right frame size and image and assign to a UIBarButtonItem. Then you can replace the backBarButtonItem from your UINavigationItem with the new UIBarButtonItem you created.
This is how I dealt with the problem using Appearance API and is working great.
When changing backButtonBackgroundImage image is automatically stretched across barButtonItem so we must resize it back to original using resizableImageWithCapInsets:.
To position it inside barButtonItem we then use imageWithAlignmentRectInsets to add caps around it. Then just assign it using setBackButtonBackgroundImage:forState:barMetrics.
Just play with the numbers and you will find the right position.
int imageSize = 24;
UIImage *barBackBtnImg = [[[UIImage imageNamed:#"backButton"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, imageSize, 0, 0)] imageWithAlignmentRectInsets:UIEdgeInsetsMake(0, -10, 0, -10)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:barBackBtnImg forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
This solution worked for me in Swift 2.1. iOS 9.2.1. (Xcode 7.2) on iPhone in portrait Mode. I have tested it on the simulators iPhone 5 and 6+ and it also worked.
import UIKit
class EVEMainNaviVC: UINavigationController
{
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
}
override func viewDidLoad()
{
super.viewDidLoad()
self.view.backgroundColor = APP_BACKGROUND_COLOR
self.setupAppNaviagtionBar()
}
private func setupAppNaviagtionBar()
{
dispatch_async(dispatch_get_main_queue())
{ () -> Void in
self.navigationBar.setHeight(55.0)
self.navigationBar.translucent = false
self.navigationBar.alpha = 1.0
self.navigationBar.barTintColor = UIColor.whiteColor()
let newBackButtonImageInset = UIEdgeInsetsMake(0, 0, -6, 0)
let newBackButtonImage = UIImage(named: "back")?.imageWithAlignmentRectInsets(newBackButtonImageInset)
self.navigationBar.backIndicatorImage = newBackButtonImage
self.navigationBar.backIndicatorTransitionMaskImage = newBackButtonImage
self.navigationBar.tintColor = CUSTOM_BUTTON_COLOR
}
}
}
I found the simplest solution I have ever seen. Just three things.
Override UINavigationBar and use it in your UINavigationController
let navigationController = UINavigationController(navigationBarClass: NavigationBar.self, toolbarClass: nil)
navigationController.viewControllers = [viewController]
Setup your indicator images:
backIndicatorImage = #imageLiteral(resourceName: "back")
backIndicatorTransitionMaskImage = #imageLiteral(resourceName: "back")
Implement layoutSubviews in your custom UINavigationBar class.
override func layoutSubviews() {
super.layoutSubviews()
subviews.forEach { (view) in
if let imageView = view as? UIImageView {
if imageView.image == backIndicatorImage || imageView.image == backIndicatorTransitionMaskImage {
view.frame.origin.y = floor((frame.height - view.frame.height) / 2.0)
}
}
}
}
That is all. :)
My goal was to position the back button image without meddling with the subviews of the UINavigationItem. So, what I did was to create an extension for UIImage that adds a padding around of the image.
extension UIImage {
public func imageWith(padding: UIEdgeInsets) -> UIImage {
let origin = CGPoint(x: padding.left, y: padding.top)
let sizeWithPadding = CGSize(width: padding.left + size.width + padding.right, height: padding.top + size.height + padding.bottom)
UIGraphicsBeginImageContextWithOptions(sizeWithPadding, false, 0.0)
draw(in: CGRect(origin: origin, size: size))
let imageWithPadding = UIGraphicsGetImageFromCurrentImageContext() ?? self
UIGraphicsEndImageContext()
return imageWithPadding
}
}
For example: if you want to move the image to the top you add the corresponding padding to the bottom.
.imageWith(padding: UIEdgeInsets(top: 0, left: 0, bottom: 2, right: 0))
I know how to remove/change UISearchBar background color around search field:
[[self.searchBar.subviews objectAtIndex:0] removeFromSuperview];
self.searchBar.backgroundColor = [UIColor grayColor];
But don't know how to do this inside it like that:
This needs to be compatible with iOS 4.3+.
Just customize the text field itself.
I am simply doing this and it works fine for me (iOS 7).
UITextField *txfSearchField = [_searchBar valueForKey:#"_searchField"];
txfSearchField.backgroundColor = [UIColor redColor];
This way you don't need to create an image, size it, etc...
Details
Xcode Version 11.0 (11A420a), swift 5
UISearchBar customising sample
Solution
import UIKit
extension UISearchBar {
func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField }
func setTextField(color: UIColor) {
guard let textField = getTextField() else { return }
switch searchBarStyle {
case .minimal:
textField.layer.backgroundColor = color.cgColor
textField.layer.cornerRadius = 6
case .prominent, .default: textField.backgroundColor = color
#unknown default: break
}
}
}
Usage
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 44))
//searchBar.searchBarStyle = .prominent
view.addSubview(searchBar)
searchBar.placeholder = "placeholder"
searchBar.setTextField(color: UIColor.green.withAlphaComponent(0.3))
Result 1
searchBar.searchBarStyle = .prominent // or default
Result 2
searchBar.searchBarStyle = .minimal
Full sample
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 44))
//searchBar.searchBarStyle = .minimal
searchBar.searchBarStyle = .prominent
view.addSubview(searchBar)
searchBar.placeholder = "placeholder"
searchBar.setTextField(color: UIColor.green.withAlphaComponent(0.3))
}
}
Solution which doesn't involve any private API ! :)
Currently (probably since iOS 5 ) you can do this, for simply one colour cases, in this way:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor redColor]];
but please keep in mind that as it basis on appearance the change will be global for the app (it can be an advantage or a disadvantage of the solution).
For Swift you can use (it will work for iOS 9 and above):
if #available(iOS 9.0, *) {
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).backgroundColor = UIColor.darkGrayColor()
}
You do not need #available if your project supports iOS 9 and newer.
If you need to support earlier versions of iOS and want to use Swift take a look at this question.
Use this code to change the searchBar's UITextField backgroundImage:
UITextField *searchField;
NSUInteger numViews = [searchBar.subviews count];
for (int i = 0; i < numViews; i++) {
if ([[searchBar.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) { //conform?
searchField = [searchBar.subviews objectAtIndex:i];
}
}
if (searchField) {
searchField.textColor = [UIColor whiteColor];
[searchField setBackground: [UIImage imageNamed:#"yourImage"]]; //set your gray background image here
[searchField setBorderStyle:UITextBorderStyleNone];
}
Use the below code to change the UISearchBarIcon:
UIImageView *searchIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"yourSearchBarIconImage"]];
searchIcon.frame = CGRectMake(10, 10, 24, 24);
[searchBar addSubview:searchIcon];
[searchIcon release];
Also, to change the searchBar icon you can use the following built-in method on UISearchBar (which is available from iOS 5+):
- (void)setImage:(UIImage *)iconImage forSearchBarIcon:(UISearchBarIcon)icon state:(UIControlState)state
Here you can set 4 types of UISearchBarIcon i.e.:
UISearchBarIconBookmark
UISearchBarIconClear
UISearchBarIconResultsList
UISearchBarIconSearch
I hope this help you...
According to the UISearchBar documentation:
You should use this function for iOS 5.0+.
- (void)setSearchFieldBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state
Usage example:
[mySearchBar setSearchFieldBackgroundImage:myImage forState:UIControlStateNormal];
Sadly, in iOS 4 you need to revert to less sophisticated methods. See other answers.
As Accatyyc says for iOS5+ use setSearchFieldBackgroundImage, but you either need to create a graphic, or do the following:
CGSize size = CGSizeMake(30, 30);
// create context with transparent background
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0,30,30)
cornerRadius:5.0] addClip];
[[UIColor grayColor] setFill];
UIRectFill(CGRectMake(0, 0, size.width, size.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.searchBar setSearchFieldBackgroundImage:image forState:UIControlStateNormal];
what about apple way?
UISearchBar.appearance().setSearchFieldBackgroundImage(myImage, for: .normal)
you can set any image on your design!
But if you want create all programmaticle, you ca do this
my solution on Swift 3
let searchFieldBackgroundImage = UIImage(color: .searchBarBackground, size: CGSize(width: 44, height: 30))?.withRoundCorners(4)
UISearchBar.appearance().setSearchFieldBackgroundImage(searchFieldBackgroundImage, for: .normal)
where i use helpers extension
public extension UIImage {
public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else { return nil }
self.init(cgImage: cgImage)
}
public func withRoundCorners(_ cornerRadius: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let rect = CGRect(origin: CGPoint.zero, size: size)
let context = UIGraphicsGetCurrentContext()
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
context?.beginPath()
context?.addPath(path.cgPath)
context?.closePath()
context?.clip()
draw(at: CGPoint.zero)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return image;
}
}
To do this on iOS 13+,
searchController.searchBar.searchTextField.backgroundColor = // your color here
Do note that by default the searchTextField.borderStyle is set to roundedRect, which applies a slight gray overlay on top of the color that you will set. If this is undesired, do
searchController.searchBar.searchTextField.borderStyle = .none
This will get rid of the gray overlay, but also get rid of the rounded corners.
I've found this to be the best way to customize the appearance of various search bar attributes in Swift 2.2 and iOS 8+ using UISearchBarStyle.Minimal
searchBar = UISearchBar(frame: CGRectZero)
searchBar.tintColor = UIColor.whiteColor() // color of bar button items
searchBar.barTintColor = UIColor.fadedBlueColor() // color of text field background
searchBar.backgroundColor = UIColor.clearColor() // color of box surrounding text field
searchBar.searchBarStyle = UISearchBarStyle.Minimal
// Edit search field properties
if let searchField = searchBar.valueForKey("_searchField") as? UITextField {
if searchField.respondsToSelector(Selector("setAttributedPlaceholder:")) {
let placeholder = "Search"
let attributedString = NSMutableAttributedString(string: placeholder)
let range = NSRange(location: 0, length: placeholder.characters.count)
let color = UIColor(white: 1.0, alpha: 0.7)
attributedString.addAttribute(NSForegroundColorAttributeName, value: color, range: range)
attributedString.addAttribute(NSFontAttributeName, value: UIFont(name: "AvenirNext-Medium", size: 15)!, range: range)
searchField.attributedPlaceholder = attributedString
searchField.clearButtonMode = UITextFieldViewMode.WhileEditing
searchField.textColor = .whiteColor()
}
}
// Set Search Icon
let searchIcon = UIImage(named: "search-bar-icon")
searchBar.setImage(searchIcon, forSearchBarIcon: .Search, state: .Normal)
// Set Clear Icon
let clearIcon = UIImage(named: "clear-icon")
searchBar.setImage(clearIcon, forSearchBarIcon: .Clear, state: .Normal)
// Add to nav bar
searchBar.sizeToFit()
navigationItem.titleView = searchBar
without using private API's:
for (UIView* subview in [[self.searchBar.subviews lastObject] subviews]) {
if ([subview isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField*)subview;
[textField setBackgroundColor:[UIColor redColor]];
}
}
For Changing Only Color :
searchBar.tintColor = [UIColor redColor];
For Applying Background Image :
[self.searchBar setSearchFieldBackgroundImage:
[UIImage imageNamed:#"Searchbox.png"]
forState:UIControlStateNormal];
A better solution is to set the appearance of the UITextField inside UISearchBar
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor grayColor]];
try this in iOS13 in swift
#IBOutlet weak var searchBar: UISearchBar!
searchBar.barTintColor = .systemIndigo
searchBar.searchTextField.backgroundColor = .white
Just traverse all views using a category method (verified in iOS 7 and doesn't use private API):
#implementation UISearchBar (MyAdditions)
- (void)changeDefaultBackgroundColor:(UIColor *)color {
for (UIView *subview in self.subviews) {
for (UIView *subSubview in subview.subviews) {
if ([subSubview isKindOfClass:[UITextField class]]) {
UITextField *searchField = (UITextField *)subSubview;
searchField.backgroundColor = color;
break;
}
}
}
}
#end
So after importing the category into your class, just use it like:
[self.searchBar changeDefaultBackgroundColor:[UIColor grayColor]];
Keep in mind, if you put this immediately after the [[UISearchBar alloc] init] line, it won't work yet since the subviews of the search bar are still being created. Put it a few lines down after you setup the rest of the search bar.
- (void)viewDidLoad
{
[super viewDidLoad];
[[self searchSubviewsForTextFieldIn:self.searchBar] setBackgroundColor:[UIColor redColor]];
}
- (UITextField*)searchSubviewsForTextFieldIn:(UIView*)view
{
if ([view isKindOfClass:[UITextField class]]) {
return (UITextField*)view;
}
UITextField *searchedTextField;
for (UIView *subview in view.subviews) {
searchedTextField = [self searchSubviewsForTextFieldIn:subview];
if (searchedTextField) {
break;
}
}
return searchedTextField;
}
This is the Swift version ( swift 2.1 /IOS 9 )
for view in searchBar.subviews {
for subview in view.subviews {
if subview .isKindOfClass(UITextField) {
let textField: UITextField = subview as! UITextField
textField.backgroundColor = UIColor.lightGrayColor()
}
}
}
iOS 13, Swift 5
searchBar.searchTextField.backgroundColor = .gray
searchBar.searchTextField.tintColor = .white
searchBar.searchTextField.textColor = .white
Searchbar now has a new instance property SearchTextField starting iOS 13,
https://developer.apple.com/documentation/uikit/uisearchbar/3175433-searchtextfield
if(#available(iOS 13, *))
searchBar.searchTextField.backgroundColor = [UIColor whiteColor];
searchBar.searchTextField.textColor = [UIColor blackColor];
else{
//API that supports below iOS 13
//This will set it for all the UISearchBars in your application
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setBackgroundColor:[UIColor whiteColor]];
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor blackColor]];
}
For iOS 9 use this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Remove lag on oppening the keyboard for the first time
UITextField *lagFreeField = [[UITextField alloc] init];
[self.window addSubview:lagFreeField];
[lagFreeField becomeFirstResponder];
[lagFreeField resignFirstResponder];
[lagFreeField removeFromSuperview];
//searchBar background color change
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setBackgroundColor:[UIColor greenColor]];
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor blackColor];
return YES;
}
Swift 3
for subview in searchBar.subviews {
for innerSubview in subview.subviews {
if innerSubview is UITextField {
innerSubview.backgroundColor = UIColor.YOUR_COLOR_HERE
}
}
}
For Swift 3+, use this:
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if let textField = subViewOne as? UITextField {
subViewOne.backgroundColor = UIColor.red
//use the code below if you want to change the color of placeholder
let textFieldInsideUISearchBarLabel = textField.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideUISearchBarLabel?.textColor = UIColor.blue
}
}
}
With Swift 4, I would recommend that you only do this, no additional code needed:
self.searchBar.searchBarStyle = .prominent
self.searchBar.barStyle = .black
You can also change .prominent to .minimal should you not want the outer background to be grey.
#EvGeniy Ilyin EvGeniy Ilyin's solution is the best.
I wrote an Objective-C version based on this solution.
Create a UIImage category, and advertise two class methods in UIImage+YourCategory.h
+ (UIImage *)imageWithColor:(UIColor *)color withSize:(CGRect)imageRect;
+ (UIImage *)roundImage:(UIImage *)image withRadius:(CGFloat)radius;
Implement methods in UIImage+YourCategory.m
// create image with your color
+ (UIImage *)imageWithColor:(UIColor *)color withSize:(CGRect)imageRect
{
UIGraphicsBeginImageContext(imageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, imageRect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
// get a rounded-corner image from UIImage instance with your radius
+ (UIImage *)roundImage:(UIImage *)image withRadius:(CGFloat)radius
{
CGRect rect = CGRectMake(0.0, 0.0, 0.0, 0.0);
rect.size = image.size;
UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect
cornerRadius:radius];
[path addClip];
[image drawInRect:rect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Make your own UISearchBar in your ViewController
CGRect rect = CGRectMake(0.0, 0.0, 44.0, 30.0);
UIImage *colorImage = [UIImage imageWithColor:[UIColor yourColor] withSize:rect];
UIImage *finalImage = [UIImage roundImage:colorImage withRadius:4.0];
[yourSearchBar setSearchFieldBackgroundImage:finalImage forState:UIControlStateNormal];
This Worked for me.
- (void)setupSearchBar
{
[self.searchBar setReturnKeyType:UIReturnKeySearch];
[self.searchBar setEnablesReturnKeyAutomatically:NO];
[self.searchBar setPlaceholder:FOLocalizedString(#"search", nil)];
[self.searchBar setBackgroundImage:[UIImage new]];
[self.searchBar setBackgroundColor:[UIColor myGreyBGColor]];
[self.searchBar setBarTintColor:[UIColor myGreyBGColor]];
[self.searchBar setTintColor:[UIColor blueColor]];
}
Use it to update search textfield backgroud_color for xcode10 and xcode11 working fine for me
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextColor:[UIColor greenColor]];
This helped me to change the background color of textField in searchbar.
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = .white
How can I add a background image to a UILabel in an iPhone Application. I've tried to do it through IB but with no result.
Try doing it with code:
Objective-C:
theLabel.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"blah"]];
Swift:
theLabel.backgroundColor = UIColor(patternImage: UIImage(named: "blah")!)
Or place an UIImageView behind the label (not recommended).
Update: placing an UIImageView behind a label was not recommended because then you would have to manage two views. But if you must do something that only an UIImageView can do this is still a good approach. I suspect that your app will actually run better this way.
if you want that image should be stretched to fill the Label width.
try this code.
UILabel *myLabel=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
UIImage *img = [UIImage imageNamed:#"a.png"];
CGSize imgSize = myLabel.frame.size;
UIGraphicsBeginImageContext( imgSize );
[img drawInRect:CGRectMake(0,0,imgSize.width,imgSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
myLabel.backgroundColor = [UIColor colorWithPatternImage:newImage];
Swift 2.2: set the Background image with background color
UIGraphicsBeginImageContextWithOptions(stationNameLabel.frame.size, false, 0.0)
let context = UIGraphicsGetCurrentContext();
let components = CGColorGetComponents(color.CGColor)
CGContextSetRGBFillColor(context, components[0], components[1], components[2], 0.4);
CGContextFillRect(context, CGRectMake(0.0, 0.0, stationNameLabel.frame.size.width, stationNameLabel.frame.size.height));
targetImage.drawInRect(CGRectMake(0.0, 0.0, stationNameLabel.frame.size.width, stationNameLabel.frame.size.height))
let resultImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
label.backgroundColor = UIColor(patternImage: resultImage)
let messageBackgroundView = UIImageView()
messageBackgroundView.image = UIImage(named: "chat-background")
if messageBackgroundView.superview != lblChatdata.superview {
lblChatdata.superview!.insertSubview(messageBackgroundView, belowSubview: lblChatdata)
messageBackgroundView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
messageBackgroundView.leadingAnchor.constraint(equalTo: lblChatdata.leadingAnchor),
messageBackgroundView.trailingAnchor.constraint(equalTo: lblChatdata.trailingAnchor),
messageBackgroundView.topAnchor.constraint(equalTo: lblChatdata.topAnchor),
messageBackgroundView.bottomAnchor.constraint(equalTo: lblChatdata.bottomAnchor),
])
messageBackgroundView.contentMode = .scaleAspectFill
}
#pixelfreak, your right. UIColor instance with color image pattern has serious performance issues when assigning it to backroundcolor
cell.cellLabel.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)