Is there any way to get the UIKeyboard background color? I am putting an accessory view on top of my UIKeyboard and is trying to match its color with the keyboard background color. But, it seems, different types of keyboard has different background colors. Please see below screenshots for default and email keyboard.
Is there any way, we can find out the background color of the keyboard programmatically so that the color of the accessoryView could be changed.
Swift 5
You can use an input view and it matches the keyboard style.
let textView = UITextView()
let frame = CGRect(x: 0, y: 0, width: 0, height: 40)
textView.inputAccessoryView = UIInputView(frame: frame, inputViewStyle: .keyboard)
You could do something like this:
UIKeyboardAppearance currentAppearance = yourTextView.keyboardAppearance;
if (currentAppearance == UIKeyboardAppearanceDark) {
// dark
}
else if (currentAppearance == UIKeyboardAppearanceDefault) {
// default
}
else if (currentAppearance == UIKeyboardAppearanceLight) {
// light
}
I suggest you to get your keyboard color's RGB from DigitalColor Meter as we use this tool in Mac or you can get it by any other tool.
And then simply assign these RGB value to your accessory view and match its color with your keyboard.
The RGB value of your keyboard is seems to me is like (63,63,63) and you can use this:
[UIColor colorWithRed:63/255.0 green:63/255.0 blue:63/255.0 alpha:1]
Hopefully it will helps you.
If you're developing a custom keyboard and trying to match the background of your keyboard's view, use this in your keyboard's view controller where you set up the view:
keyboardView.backgroundColor = view.backgroundColor
My viewDidLoad() in my keyboard's view controller looks like:
var keyboardView: UIView!
let keyboardNib = UINib(nibName: "KeyboardView", bundle: nil)
keyboardView = keyboardNib.instantiate(withOwner: self, options: nil)
[0] as? UIView
keyboardView.frame.size = view.frame.size
keyboardView.backgroundColor = view.backgroundColor
view.addSubview(keyboardView)
For the dark background use
mytextfield.keyboardAppearance = UIKeyboardAppearanceAlert;
Related
I understand that this question has been asked many, many times on SO. However, as Apple does best, with the release of iOS 11, they seem to have made a seemingly unnecessary change to the UISearchBar, specifically it's view hierarchy.
In further, the "text field" of a search bar is no longer accessible in the search bar's subviews, causing all of the previous solutions to "access" and change the background color of the text field, or any property of the text field for that matter.
Does anyone know how to actually adjust the background color of a search bar in iOS 11?
FYI:
I am specifically talking about the color behind the text... which now as of 11 defaults to white unless you specify the search bar style to be minimal.
UPDATE 1:
Since my posting of this question, I still have not found a valid or really any real solution to this issue. The closest I have seem to come is to dive deep into the appearance for instance properties
[[UISearchBar class] appearanceWhenContainedInInstancesOfClasses:(nonnull NSArray<Class<UIAppearanceContainer>> *)]
of the UISearchBar. Playing around with the found UITextField via methods such as the following:
if ([view isKindOfClass:[UITextField class]]) {
return (UITextField*)view;
}
UITextField *searchTextField;
for (UIView *subview in view.subviews) {
searchTextField = [self searchViewForTextFieldBg:subview];
if (searchTextField) {
break;
}
}
return searchTextField;
you can begin drawing a new background view to be placed behind the view. However, the issues I had found too tedious to pursue further were drawing the a view with the correct frame / bounds to mimic exactly the original background.
Hopefully someone can find the actual solution to this problem. Nice miss apple...
I think you may be looking for this, right? But I've it in Swift :(
#IBOutlet weak var sbSearchBar: UISearchBar!
if let textfield = sbSearchBar.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.blue
textfield.backgroundColor = UIColor.yellow
}
Here is result:
This Swift code changes the background color of the text field:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// background color of text field
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = .cyan
}
This is the result
let searchBar = UISearchBar(frame: CGRect())
let searchField: UITextField? = searchBar.value(forKey: "searchField") as? UITextField
let searchBarBackground: UIView? = searchBar.value(forKey: "background") as? UIView
// searchBarBackground?.removeFromSuperview()
if searchField != nil {
var frame = searchField?.frame
frame?.size.height = 30
searchField?.frame = frame!
searchField?.backgroundColor = .yellow
}
searchBar.barTintColor = .red
searchBar.delegate = self
searchBar.backgroundColor = .green
Runtime Views Hierarchy
If we set background colors for UISearchBar with code above, we'll see the colored subviews as follow images(click links to see).

backgroundColor for Superview of UISearchBar subviews
We can see the Class Name of green view is UISearchBar in Object inspector.
So, if we use searchBar.backgroundColor = .green, we'll set the backgroundColor of Superview green. Therefore, the UISearchBar instance property backgroundColor will set the superview's background color.
Superview of UISearchBar
barTintColor for UISearchBarBackground
We can see the Class Name of red view is UISearchBarBackground in Object inspector.
However, there's no direct method to access the view, we can use KVC searchBar.value(forKey: "background") as? UIView try to get searchBarBackground.
If we use searchBar.barTintColor = .red, we'll set the backgroundColor of UISearchBarBackground's view red. In order to remove two black border on the tint bar layer, we have to remove the background from superview.
barTintColor of UISearchBar
searchField?.backgroundColor for UITextField
We can see the Class Name of yellow view is _UISearchBarSearchFieldBackgroundView (Subview of UISearchBarTextField) in Object inspector.
There's no direct method to access the searchField, same as searchBarBackground. We can also use KVC searchField: UITextField? = searchBar.value(forKey: "searchField") as? UITextField try to get searchField.
If we use searchField?.backgroundColor = .yellow, we'll set the backgroundColor of UITextField yellow. Therefore, if we want to set text field background color, we have to access the searchField with KVC first
UITextField of UISearchBar
It's much simpler than that in Swift 5.
searchBar.barTintColor = .black
searchBar.searchTextField.backgroundColor = .white
Swift 4-5
searchController.searchBar.barTintColor = .white
I am trying to add a gradient background to my picker in the same way that I have added a gradient background to my VC.
When I do this via the code below, the gradient is added but the text disappears from view. Although the picker still behaves as if the text is there.
My guess is it's something to do with the .insertSublayer placing the gradient background over the top off the text.
override func viewDidLoad() {
let background = CAGradientLayer().bespokeColor()
background.frame = self.view.bounds
self.view.layer.insertSublayer(background, at: 0)
let pickerBackground = CAGradientLayer().bespokeColor()
pickerBackground.frame = self.Picker.bounds
self.Picker.layer.insertSublayer(pickerBackground, at: 0)
}
How do I get around this?
So i am using a custom function to format an subview that I am adding to a UICollectionViewCell. It is from Brian Voong's public project here: https://github.com/purelyswift/facebook_feed_dynamic_cell_content/blob/master/facebookfeed2/ViewController.swift.
func addConstraintsWithFormat(format: String, views: UIView...) {
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerate() {
let key = "v\(index)"
viewsDictionary[key] = view
view.translatesAutoresizingMaskIntoConstraints = false
}
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))
}
What is interesting, is that in my UICollectionView I add a SubView to a single cell, and set the background color to white. The background is white when I comment out the line which sets the background for the subview, and no background color is set when I uncomment out the line setting the visually formatted constraints for the subview.
Here are the two lines which clobber each other:
func chronicleOneClicked(sender: UIButton) {
point1view.backgroundColor = UIColor.whiteColor()
addSubview(point1view)
//When the below is commented the background of point1view disappears
//addConstraintsWithFormat("|-50-[v0]-50-|", views: point1view)
}
when I do print(subviews) i see that the UIView with the white background color is the highest in the view stack (top of the stack). When i print out subviews[subviews.count-1].backgroundColor I get the Optional(UIDeviceWhiteColorSpace 1 1) which is what I expect. it is strange because the color is not displayed.
I am not sure how to go about seeing what is happening behind the scenes to confirm that the background is being set at all in the latter case.
This all happens in a class for the UiCollectionViewCell which I am using as the class of one of my UICollectionView Cells which can be viewed in its entirety here:
https://gist.github.com/ebbnormal/edb79a15dab4797946e0d1f6905c2dd0
Here is a screen shot from both cases, the first case is where the line addConstraintsWithFormat is commented out, and the second case is where it is uncommented: The subview of point1subview is highlighted with a white background in the first case.
This is how I setup the views. It all happens in a class that overrides UICollectionViewCell
class myClass : UICollectionViewCell {
var chronicle: BrowsableChronicle? {
didSet{
//etc.
point1.addTarget(self, action: #selector(chronicleOneClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let point1 : PointButtonView = {
let pointView = PointButtonView(frame: CGRectMake(0, 0, 25, 25 ))
return pointView
}()
//NOTE here is where I create the view, whose background doesn't display
let point1view : UIView = {
let pointView = UIView(frame: CGRectMake( 0, 0, 200, 270))
pointView.backgroundColor = UIColor.whiteColor()
let title = UILabel(frame: CGRectMake(0, 0, 200, 21))
title.font = UIFont(name:"HelveticaNeue-Bold", size: 16.0)
pointView.addSubview(title)
let summary = UILabel(frame: CGRectMake(0, 0, 190, 260))
summary.lineBreakMode = NSLineBreakMode.ByWordWrapping
summary.numberOfLines = 4
summary.font = UIFont(name:"HelveticaNeue", size: 12.5)
pointView.addSubview(summary)
let button = UIButton(frame: CGRectMake(0, 200, 190, 30))
button.backgroundColor = UIColor(red:0.00, green:0.90, blue:0.93, alpha:1.0)
pointView.addSubview(button)
pointView.tag = 100
return pointView
}()
//NOTE: here is where I add the subview to the UICollectionViewCell view
func chronicleOneClicked(sender: UIButton){
addSubview(point1view)
addConstraintsWithFormat("H:|-20-[v0]-20-|", views: point1view)
//TODO anytime i add a constraint here the background color leaves!
print(subviews[subviews.count-1].backgroundColor) //Prints white
}
}
UPDATE: I thought maybe it was related to this issue :
UITableViewCell subview disappears when cell is selected
Where the UICollectionViewCell is selected, and therefore iOS automatically sets the backgroundColor to clear. The problem is, that I implemented this class extension of UIView to see when didSet is called on the backgroundColor and when it is set to clear, i set it to white. However, it only calls didSet on the backgroundColor once, when i first set the color of the view. Here is the code I used to override the UIView class:
class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
print("background color is being set")
if backgroundColor == UIColor.clearColor() {
print("set to a clear color")
backgroundColor = UIColor.whiteColor()
}
}
}
}
The difference you are seeing is obviously caused by a view frame resulting in zero width or zero height.
Let's explain how the drawing system works.
Every view has a layer that draws its background color in its bounds, which are specified by the view frame. Then every subview is drawn. However, the subviews are not limited by the frame unless you set UIView.clipsToBounds to true.
What you are seeing means the a container view has a zero frame (either width or height) but its subviews have correct frame, therefore they are displayed correctly.
There are multiple reasons why this could happen, for example:
You are setting translatesAutoresizingMaskIntoConstraints to false to some system view (e.g. the content view of the UICollectionView).
You have a constraint conflict, resulting in some important constraint to be removed (you should see a warning).
You are missing some constraints. Specifically, I don't see you setting vertical constraints.
You should be able to debug the problem using the view debugger in Xcode. Just open your app, click the view debugger button and print the recursive description of the cell. You should see a frame that is zero.
as the topic already says, i try to create a small line on top of my UIKeyboard appearance. The reason is, if i pop up the white keyboard while having a white background, it looks just awful.
One idea would be to create a thin 1px line and place it on the bottom, hide it and show it whenever there is the keyboard displayed and align it with auto layout. The disadvantage of this idea is to do it in every view.
Thanks for your ideas.
Every UITextField and UITextView has an inputAccessoryView property (inherited from the UIResponder superclass). When one of these views becomes first responder and the system presents the on-screen keyboard, the system automatically displays the inputAccessoryView of the first responder along the top of the keyboard. For example, in this answer, the dark bar with the left and right arrows and the “Done” button is an inputAccessoryView.
So the easiest way for you to get a thin line on top of the keyboard is probably to create a one-point tall view and set it as the inputAccessoryView of your text field or text view. Set the background color of the accessory view to a dark color.
Easiest way to do this to add an inpustAccessoryView for textFiled when it becomes first responder and the system presents the on-screen keyboard.
Try this out:
Swift 3:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let separatorView = UIView(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1))
separatorView.backgroundColor = UIColor.lightGray
textField.inputAccessoryView = separatorView
return true
}
So as Rob already wrote, the AccessoryView is the correct and smoothest solution, because Apple solves all animations, displaying and so on, in a correct way so no worry to take care about anything else.
I solved it as an extension. I wanted it to display a small devider on the bottom so i have a closed Numeric keyboard:
Swift 2.0:
extension UITextField {
override public func becomeFirstResponder() -> Bool {
self.addSeparatorInputAccessoryIfNumericKeyboardOnPhone()
return super.becomeFirstResponder()
}
func addSeparatorInputAccessoryIfNumericKeyboardOnPhone() {
guard self.keyboardType == .NumberPad else {
return
}
guard UIDevice.currentDevice().userInterfaceIdiom == .Phone else {
return
}
let view = UIView(frame: CGRectMake(0, 0, 0, 1 / UIScreen.mainScreen().scale))
view.backgroundColor = UIColor.lightGrayColor()
self.inputAccessoryView = view
}
}
I am trying to make a blurred background the UITabBar for my UITabViewController, and the idea is to have it be blurred and transparent so that the views underneath can be seen scrolling by.
Unfortunately I cannot for the life of me get the tab bar to be transparent. No matter what I do, there is always some black background to the tab bar that prevents the underlying view controllers from showing through.
If I change the alpha of the UITabBar to something low I can see that the tableview is indeed behind it, however you can see that the UITabBar has some sort of background to it that is preventing the tableview from fully showing through (and I don't want to bar button items to be invisible, just the tab bar background).
How can this be?
In the custom tab bar's view did load I have:
self.tabBar.translucent = true
self.tabBar.alpha = 0.3
self.tabBar.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.0)
self.tabBar.layer.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.0).CGColor
self.tabBar.backgroundImage = nil
self.tabBar.shadowImage = nil
and in the AppDelegate I have:
UITabBar.appearance().barTintColor = UIColor.clearColor()
UITabBar.appearance().tintColor = kColorAccent
UITabBar.appearance().translucent = true
UITabBar.appearance().translucent = true
UITabBar.appearance().backgroundColor = UIColor.clearColor()
UITabBar.appearance().backgroundImage = nil
UITabBar.appearance().layer.backgroundColor = UIColor.clearColor().CGColor
UITabBar.appearance().shadowImage = nil
...yeah It's excessive but I want to try everything.
Any ideas on what to do?
Make a UITabBar transparent
Assign a clear image to its backgroundImage. You can use a 1x1 clear.png, or create one programmatically:
self.backgroundImage = UIImage.imageWithColor(UIColor.clearColor())
This will make the UITabBar transparent:
Add a blur effect
Insert a UIVisualEffectView as the rearmost subview.
let frost = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
frost.frame = self.bounds
self.insertSubview(frost, atIndex: 0)
This will insert a UIBlurEffect (frost):
Example
Set the Custom Class for the UITabBar of the Tab Bar Controller to FrostyTabBar.
You have a few options to supply a clearColor image. You can create a clear.png image with an alpha of 0. A programmatic elegant solution is described here.
If using a clear.png, assign it to the Background Image in the Attribute Inspector:
In Interface Builder, pick Style: Default & Translucent.
Once you take control of the background blur with a UIVisualEffectView, you can in turn supply any UIVisualEffect you so desire.
The entire FrostyTabBar class looks like this:
import UIKit
class FrostyTabBar: UITabBar {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let frost = UIVisualEffectView(effect: UIBlurEffect(style: .light))
frost.frame = bounds
frost.autoresizingMask = .flexibleWidth
insertSubview(frost, at: 0)
}
}
► Find this solution on GitHub and additional details including a 1x1 clear.png on Swift Recipes.
I found a prefect solution, you only need to subclass UITabBar and then do the following actions to clean that annoying views
class MainTabBar: UITabBar {
var cleanDone = false
override func layoutSubviews() {
super.layoutSubviews()
self.deleteUnusedViews()
}
func deleteUnusedViews() {
if !self.cleanDone {
var removeCount = 0
for (_, eachView) in (self.subviews.enumerate()) {
if NSStringFromClass(eachView.classForCoder).rangeOfString("_UITabBarBackgroundView") != nil {
eachView.removeFromSuperview()
removeCount += 1
}
if NSStringFromClass(eachView.classForCoder).rangeOfString("UIImageView") != nil {
eachView.removeFromSuperview()
removeCount += 1
}
if removeCount == 2 {
self.cleanDone = true
break
}
}
}
}
}
the only solution that worked for me was this:
UITabBar.appearance().shadowImage = UIImage()
UITabBar.appearance().backgroundImage = UIImage()
and set: (you can do this in storyboard as well)
UITabBar.appearance().barTintColor = UIColor.clear
but what i have to set in storyboard is:
tabbar : translucent -> true