Change UISearchBar textColor not working - google-maps

I am using google places API for autoComplete widget. I am showing the full screen control in ios 9+ using swift. I am adding a full control as given in the docs.
I have added the code as shown in the docs. Now I want to change the searchBar text color to whiteColor.
So I tried this
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).textColor = UIColor.whiteColor()
But I am not getting the desired behaviour. Below is the screenshot
This has been given in Docs
https://developers.google.com/places/ios-api/autocomplete#use_a_table_data_source
But this is not working. I need help with regarding to this.

You need to create an extension like follwoing:
public extension UISearchBar {
public func setNewcolor(color: UIColor) {
let clrChange = subviews.flatMap { $0.subviews }
guard let sc = (clrChange.filter { $0 is UITextField }).first as? UITextField else { return }
sc.textColor = color
}
}
And change color using following code:
controller.searchBar.setNewcolor(UIColor.redColor())
Output is :
Update:
For the change color of searchBar text for the GMSAutocompleteViewController you need to do following code:
let searchBarTextAttributes: [String : AnyObject] = [NSForegroundColorAttributeName: UIColor.redColor(), NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())]
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).defaultTextAttributes = searchBarTextAttributes
That change the text out put like following image:
And if you wish to change placeholder text and it's color for searchBar. You need to do following code:
let placeholderAttributes: [String : AnyObject] = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())]
let attributedPlaceholder: NSAttributedString = NSAttributedString(string: "Find a place", attributes: placeholderAttributes)
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).attributedPlaceholder = attributedPlaceholder
It will be show like:

Use Bellow code for Swift 3
if #available(iOS 9.0, *) {
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSForegroundColorAttributeName: UIColor.green]
} else {
// Fallback on earlier versions
}
Hope this helps.

For swift 4 ios 12
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes
.updateValue(UIColor.white, forKey: NSAttributedStringKey.foregroundColor.rawValue)

You can use UIAppearance protocol to get the appearance proxy for a class which is available in iOS 5.0 and later.
There are actually two ways to customize appearance for objects and to get the appearance proxy for the class.
To customize the appearance of all instances of a class, use appearance.
To customize the appearances for instances of a class when contained within an instance of a container class, or instances in a hierarchy, use appearanceWhenContainedIn.
You can apply this sample code:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
You can also try another option given in this SO post - UISearchBar text color change in iOS 7.
I hope that covers your issue. Happy coding!

In swift 5:
let searchBarTextAttributes: [NSAttributedString.Key : AnyObject] = [NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue): UIColor.red, NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue): UIFont.systemFont(ofSize: 14.0)]
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = searchBarTextAttributes

This is actually very easy, just access the textField inside that searchBar as so:
searchBar.searchTextField.defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.red]

Lastest on swift 5
searchBar.searchTextField.textColor = .white

Related

Transport bar live label in AVPlayerViewController (tvOS only)

It seems impossible to disable or change the red backgrounded LIVE label in the AVPlayerViewController's transport bar on tvOS 15.2. Also, it is enabled by default ever since 15.2 came out. Here is a picture of the label shown here:
I have tried to play around with some of the available options like this one:
guard let pvc = playerRenderController as? AVPlayerViewController else { return }
pvc.transportBarIncludesTitleView = false
It does hide the LIVE label but it also hides the title (Straight Rhythm) from the image.
Furthermore, the label text seems to be specific to the locale, so in Danish it would be DIREKTE instead of LIVE.
Here is a video that showcases this feature (time 03:08):
Any suggestions on how to hide/change this label?
Hello I found a workaround to do it.
After you play the stream call this function with parameters the playerViewController.view
private func removeLiveLabel(view: UIView) {
let list = ["_AVPlayerViewControllerContainerView", "_AVFocusContainerView", "UIView"]
for subview in view.subviews where list.contains(String(describing: type(of: view))) {
for subSubview in subview.subviews {
if subSubview.value(forKey: "class").debugDescription.contains("_AVxOverlayPlaybackAuxiliaryMetadataView") {
subSubview.removeFromSuperview()
return
}
}
removeLiveLabel(view: subview)
}
}
This function will search the subviews of the AVPlayerViewController object controls and will remove the badge from the view without removing the Title.

Possible to use named color from asset catalog in webview?

Is there any shortcut which would enable us to directly use a named / dynamic iOS color within a WebView?
I mean, the iOS knows all named colors - why not inject those into the webview?
This is what I tried and which failed to work:
<div style="color:systemBackground">Test</div>
I know that HTML and app assets are two different domains, but maybe someone knows an elegant shortcut.
I guess it could be a 2-step process. The 2nd step would replace web colors with dynamic / named colors:
let html = "Hello <u><b style='color:red'>World!</b></u>"
let data = html.data(using: .utf8)!
let string = try! NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
// we now replace all colors with appropriate dynamic ones
string.enumerateAttribute(.foregroundColor, in: NSRange(0..<string.length)) { value, range, stop in
if let color = value as? UIColor {
if color.cgColor.components == UIColor.red.cgColor.components {
string.addAttribute(.foregroundColor, value: UIColor.systemRed, range: range)
} else {
string.addAttribute(.foregroundColor, value: UIColor.label, range: range)
}
}
}

Can you display a html <img> tag inside a UILabel in Swift?

Can you show a html <img src=''> inside a NSAttributedString used in an UILabel?
Yes you can, even though Apple doesn't recommended it:
The HTML importer should not be called from a background thread (that is, the options dictionary includes documentType with a value of html). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.
An UILabel's attributedText can be used to render html img tags.
Here an example:
let str = "<img src='https://www.codeterritory.com/assets/screenshot_sidiusnova_04-f5422e9916fb114e73484758278c284e.jpg'>"
let data = str.data(using: String.Encoding.unicode)!
do {
let attrStr = try NSAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html], documentAttributes: nil)
let label = UILabel(frame: UIScreen.main.bounds)
label.attributedText = attrStr
UIApplication.shared.windows.first!.addSubview(label)
} catch let error {
print(error)
}

swift: The HTML data converted to NSAttributed string doesn't make the links clickable in label

I have a text in HTML format. I am using the property of NSAttributed string to parse it. It pareses the text nicely and displays on the label. However, the parsing of the anchor tag doesn't make the link clickable. This is the following code that I am using for parsing.
extension String {
var htmlToAttributedString: NSAttributedString? {
guard let data = data(using: .utf8) else { return NSAttributedString() }
do {
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
return NSAttributedString()
}
}
var htmlToString: String {
return htmlToAttributedString?.string ?? ""
}
When I run the app and give the value to the label as:
text = "<p>This is Google Home</p>"
simpleTextLabel.attributedText = text.htmlToAttributedString
The output on the iOS App looks like following but nothing happens on clicking :
This is Google Home.
How can I make it open in safari?
From your line:
simpleTextLabel.attributedText = text.htmlToAttributedString
We can assume that simpleTextLabel is a UILabel.
It's basic behavior from a UILabel to not be "interactable". You can add a tap gesture on it, but it transform it as a UIButton.
There are some tricks to make it possible with a UILabel, find where exactly it has been tapped, check if there is a link, etc.
Looking for "UILabel Clickable": Create tap-able "links" in the NSAttributedString of a UILabel? etc. There are even a few third party libs.
I (in my humble opinion) consider it as a "hack".
There is a good WWDC 2018 Session: TextKit Best Practices. At 2:34, it explains that if you need to interact with a shown text, prefers UITextView over UILabel.
There is a UITextViewDelegate method just for that: textView(_:shouldInteractWith:in:interaction:)
Note that there a small differences in the rendering of a UITextView and a UILabel. If you superpose them, they won't have the same "start point", the layout is a little different. However, with small changes, it can be the same (for instance: How can I make a UITextView layout text the same as a UILabel?).
Note also that according to the small modifications of a UITextView into a UILabel visual rendering, the user won't notice the difference (and that's in fact what matters, beside that using native methods of the UITextView/UITextViewDelegate make it easily understandable afterwards by another developer, or in a few months if you need to do a small modification).

Sending data from one uiviewcontroller to another navigationcontroller using present modally

I am new to swift i am using storyboard and have used navigationcontrollers to connect from one viewcontroller to another. I want to send the name of the image clicked to the next viewcontroller which is connected modally in storyboard from the imageView. I searched lot about transferring data from oneviewcontroller to another viewcontroller connected with navigationcontroller modally but no solution was available. Please let me know if any of the code is required as i dont know how to go ahead with it. I know this might be silliest question but posting this after searching a lot on net.
EDIT according to #uraimo reply.
Do i need to provide name to every segue i created on storyboard?.
I have 2 fixed images on viewcontrollerA and i have placed a uibutton with transparent background and no text on each of them and then ctrl drag to navigation controller of viewcontrollerB for presenting modally and unwinding the backbutton i.e. UIBarButtonItem to viewcontrollerA by ctrl drag the back button of viewcontrollerB to exit of the viewcontrollerB and unwinding it.
This is how i have created navigation from any of the image click out of 3 images of viewcontrollerA to viewcontrollerB and back to viewcontrollerA on back button click of viewcontrollerB.
Please let me know if i am doing anything wrong and will your prepareForSegue code be useful in accomplishing my task.
Basically, both using IB or when you do it programmatically, you have to configure your new viewcontroller with all the data it needs before the segue is performed (or the controller is presented via code).
In your case, just set the image name (your custom view controller class YourViewController should have a specific String property to hold this value) overriding prepareForSegue in the current view controller class:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "yourModalSegueIdentifier" {
let imgName= (sender as! UIImageView)
let destination = segue.destinationViewController as UINavigationController
let yourController = destination.topViewController as YourViewController
yourController.imageName= <name here>
}
}
This solves the passing data question.
But in your case, you need the name of the clicked image, and that can be only obtained adding a click event through a UIGestureRecognizer to the UIImageView.
So, you'll need a uigesturerecognized that on click will perform the segue you've created. And also, you will not be able to get the name of the image asset (the one you use the creating an UIImage using imageNamed:) because it's not available anymore, and yo'll have to use the accessibilityIdentifier.
This makes everything way more complicated, it seems it could be done for the most part graphically here and here(but it's not really clear how to do it), but it's usually done via code.
Simplifying it a bit using a global variable:
var currentImage = ""
func viewDidLoad(){
...
...
let aTap = UITapGestureRecognizer(target: self, action: Selector("imageTapped:"))
aTap.numberOfTapsRequired = 1
//For every image, configure it with recognizer and accessibilityId:
firstImage.userInteractionEnabled = true
firstImage.addGestureRecognizer(aTap)
firstImage.accessibilityIdentifier = "firsImage"
...
}
func imageTapped(recognizer:UITapGestureRecognizer) {
let imageView = recognizer.view as! UIImageView
currentImage = imageView.accessibilityIdentifier
self.performSegueWithIdentifier("yourModalSegueIdentifier", sender: self)
}
And change this:
yourController.imageName= <name here>
to this:
yourController.imageName= currentImage
Update:
Do i need to provide name to every segue i created on storyboard?
Yes, it's the only way to identify them, every UIStoryboardSegue has an identifier. But remember, segues are not the only way to go from a controller to another, if you do it completely programmatically (no segues) you usually call "presentViewController". Segues are a storyboard concept.
Again, regarding the segue name/identifier, you didn't need it until now because you never referenced that segue from your code, you need it for both prepareForSegue and performSegueWithIdentifier. Just select the segue and give it a name on the right inspector pane.
The structure you describe seems ok, the only thing it's that i'm not so sure that the UIButtons are really needed, try with a modal segue from the imageview or directly from the viewcontroller to the destination view controller.
Update 2:
If you are starting and need a free course that will teach you the basics and also make you build a few interesting ios apps i recommend hackingwithswift.
check out how I did this
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch(segue.identifier ?? "") {
case "AddItem":
let destination = segue.destination as? UINavigationController
guard let itemViewController = destination?.topViewController as? ItemViewController else {
fatalError("Unexpected destination: \(segue.destination)")
}
itemViewController.collection = collection
case "EditCollection":
guard let collectionViewController = segue.destination as? EditCollectionViewController else {
fatalError("Unexpected destination: \(segue.destination)")
}
collectionViewController.collection = collection
default:
fatalError("Unexpected Segue Identifier; \(segue.identifier)")
}
}