Use UITabBarSystemItem icons with other buttons - ios

Is there a way to use UITabBarSystemItem icons with other buttons (e.g. UIButton, UIBarButtonItem) just with code, that is, without using external images?

I found a workaround for this, by accessing UITabBarItem subviews and retrieving the UIImageView that contains the icon.
func getImageFrom(tabBarSystemItem: UITabBarSystemItem, blueColored: Bool) -> UIImage? {
let tabBar = UITabBar()
let item = UITabBarItem(tabBarSystemItem: tabBarSystemItem, tag: 0)
tabBar.items = [item]
if blueColored { // gray otherwise
tabBar.selectedItem = item
}
let itemView = tabBar.subviews[0]
let imageView = itemView.subviews[0] as? UIImageView
//let label = itemView.subviews[1] as? UILabel // this is 'item' label
return imageView?.image
}
Usage:
let buttonImage = getImageFrom(tabBarSystemItem: .more, blueColored: true)
It's worthy to mention that using icons improperly may violate iOS Human Interface Guidelines and cause your app to be rejected from App Store. Read.

Related

icons and their color are updating automatically | iOS | CarbonKit

I'm using CarbonTabSwipeNavigation in my code (as follows). The issue is that the colour of all the icons is being updated automatically (probably to some default colour). How to fix that?
Apart from that, one of my icons is being updated (don't know why). I tried using the same icon in other parts of the application and it worked perfectly fine. Please help me in this. Thanks
weak var tab: CarbonTabSwipeNavigation!
override func viewDidLoad() {
super.viewDidLoad()
let iconNames = ["icn_events", "icn_places", "icn_activities", "icn_clubs"]
var images = [UIImage]()
for icon in iconNames {
if let img = UIImage(named: icon) {
images.append(img)
}
}
let carbonTabSwipeNavigation = CarbonTabSwipeNavigation(items: images, delegate: self)
carbonTabSwipeNavigation.pagesScrollView?.isScrollEnabled = false
carbonTabSwipeNavigation.insert(intoRootViewController: self)
//I'm using following piece of code to fix the color issue (please note, even without this, the image is being updated).
//carbonTabSwipeNavigation.setNormalColor(UIColor(hex: "5603ad"))
//carbonTabSwipeNavigation.setSelectedColor(UIColor(hex: "5603ad"))
carbonTabSwipeNavigation.setTabExtraWidth(45)
tab = carbonTabSwipeNavigation
}
I've attached the actual icon and the screenshot of how it's being displayed.
It was happening because of bar tint color. The issue was fixed the issue by image rendering mode:
let iconNames = ["icn_events", "icn_places", "icn_activities"]
var images = [UIImage]()
for icon in iconNames {
if let img = UIImage(named: icon) {
images.append(img)
}
}
if let img = UIImage(named: "icn_clubs")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal) {
images.append(img)
}

Swift 3 ios: UILabel needs to appear on top of a UIImage when the Image appears

So I am trying to give the user the ability to design their own virtual business card where the user can drag a label around the UIView, they can change background color of the UIView, as well as the color of the UILabel. The card itself is represented by a nib and the user selects the different color choices or template image choices through a UIPickerView. I want the Label to appear on top of the Image when it appears and is dragged to that part of the View, however it is not currently doing that. Changing colors of the background for the UIView and the text work just fine; I am also able to add and remove the Template image (which is a PNG) by using .isHidden().
My Problem is that when the UIImage is added to the UIView it is on top of the UILabel. If part of the UILabel overlaps with part of the png image it disappears behind it, and I would like it to appear over the image.
The code for the nib is in userCardView.swift and the picker view is on the mainViewController where I set the UserDefaults which works fine.
class userCardView: UIView {
#IBOutlet var cardView: UIView!
#IBOutlet weak var testLBL: UILabel!
#IBOutlet weak var templateImage: UIImageView!
var colorIndex = ["Black", "White", "Gray"]
var templateIndex = ["None", "Triangle"]
override func awakeFromNib() {
super.awakeFromNib()
cardView.clipToBounds = true
let backColorObject = UserDefaults.standard.object(forKey: "backGroundColor") as? String
let textColorObject = UserDefaults.standard.object(forKey: "textColor") as? String
let templateColorObject = UserDefaults.standard.object(forKey: "templateColor") as? String
let templateImageObject = UserDefaults.standard.object(forKey: "templateImage") as? String
for _ in templateIndex {
if templateImageObject == templateIndex[1] {
templateImage.isHidden = false
templateImage.image = UIImage(named: "test_triangle.png")
//testLBL.bringSubview(toFront: templateImage)
templateImage.bringSubview(toFront: testLBL)
} else if templateImageObject == templateIndex[0] {
templateImage.isHidden = true
} else {
templateImage.isHidden = true
}
}
I'm Still pretty new to using swift so any help at all would be greatly appreciated, thank you.
You need to ask testLBL's superview to bring it to the front. Your code templateImage.bringSubview(toFront: testLBL) won't work if templateImage is not the parent view of testLBL because testLBL is not in templateImage's view hierarchy.
So try to use the superview of testLBL
<testLBL's parent view>.bringSubview(toFront: testLBL)
or
testLBL.parentView.bringSubview(toFront: testLBL)
Hope it solves your problem

how to copy one view to another view in Swift

I want to copy one UIView to another view without making it archive or unarchive.
Please help me if you have any solution.
I tried with by making an extension of UIView as already available an answer on Stack over flow. But its crashing when I pass the view with pattern Image Background color.
The code related to my comment below:
extension UIView
{
func copyView() -> UIView?
{
return NSKeyedUnarchiver.unarchiveObjectWithData(NSKeyedArchiver.archivedDataWithRootObject(self)) as? UIView
}
}
I've just tried this simple code in a Playground to check that the copy view works and it's not pointing the same view:
let originalView = UIView(frame: CGRectMake(0, 0, 100, 50));
originalView.backgroundColor = UIColor.redColor();
let originalLabel = UILabel(frame: originalView.frame);
originalLabel.text = "Hi";
originalLabel.backgroundColor = UIColor.whiteColor();
originalView.addSubview(originalLabel);
let copyView = originalView.copyView();
let copyLabel = copyView?.subviews[0] as! UILabel;
originalView.backgroundColor = UIColor.blackColor();
originalLabel.text = "Hola";
originalView.backgroundColor; // Returns black
originalLabel.text; // Returns "Hola"
copyView!.backgroundColor; // Returns red
copyLabel.text; // Returns "Hi"
If the extension wouldn't work, both copyView and originalView would have same backgroundColor and the same would happen to the text of the labels. So maybe there is the possibility that the problem is in other part.
Original Post
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.hidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotViewAfterScreenUpdates(true)
viewforCopy.hidden = true
return viewCopy
}
Updated for Swift 4
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.isHidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotView(afterScreenUpdates: true)
viewforCopy.isHidden = true
return viewCopy!
}

Accessibility Voice Over loses focus on Segmented SubView

I'm working on an Accessibility project where I have a segmentedController in the NavigationBar. Almost everything is working fine until the focus comes at the middle (2/3) SegmentedController. It won't speak the the accessibilityLabel..
See my code.
I'm using NSNotifications to let the 'UIAccessibilityPostNotification' know when to focus:
func chatLijst() {
let subViews = customSC.subviews
let lijstView = subViews.last as UIView
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, lijstView)
}
func berichtenLijst() {
let subViews = customSC.subviews
let messageView = subViews[1] as UIView
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, messageView)
}
func contactenLijst() {
let subViews = customSC.subviews
let contactenView = subViews.first as UIView
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, contactenView)
}
func setupSegmentedController(){
let lijst:NSString = "Lijst"
lijst.isAccessibilityElement = false
lijst.accessibilityLabel = "Lijst met gesprekken"
let bericht:NSString = "Bericht"
bericht.isAccessibilityElement = false
bericht.accessibilityLabel = "Bericht schrijven"
let contacten:NSString = "Contacten"
contacten.isAccessibilityElement = false
contacten.accessibilityLabel = "Contacten opzoeken"
let midden:CGFloat = (self.view.frame.size.width - 233) / 2
customSC.frame = CGRectMake(midden, 7, 233, 30)
customSC.insertSegmentWithTitle(lijst, atIndex: 0, animated: true)
customSC.insertSegmentWithTitle(bericht, atIndex: 1, animated: true)
customSC.insertSegmentWithTitle(contacten, atIndex: 2, animated: true)
customSC.selectedSegmentIndex = 0
customSC.tintColor = UIColor.yellowColor()
customSC.isAccessibilityElement = true
self.navigationController?.navigationBar.addSubview(customSC)
}
Fix
Strange enough I had to restructure the subViews array in the setup func and replace UIAccessibilityPostNotification object with the new segmentsView array.
func chatLijst() {
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, segmentsViews[0])
}
// Restructure subviews....
segmentsViews = [customSC.subviews[2], customSC.subviews[1], customSC.subviews[0]]
I'm using NSNotifications to let the 'UIAccessibilityPostNotification' know when to focus
Don't. That's a poor way to build a custom accessible control, and more importantly it can be confusing to the user. The screen changed notification doesn't just change focus, it also plays a specific sound that indicates to the user that the contents of the screen has changed.
Instead, I would recommend that you either make the subviews that you want appear as accessibility elements be accessibility elements with their own labels and traits and then rely on the OS to focus and activate them, or that you implement the UIAccessibilityContainer protocol in your custom control and then rely on the OS to focus and activate them.

How to change the color of the UISearchBar Icon?

I don't know how to modify the original searchIcon's color.
The searchIcon is located in the leftView of the searchTextField. Since this is accessible we can easily set the tintColor for the view. The tintColor is also used for the searchIcon.
So in your code you can change the search icon to white with the following code:
searchBar.searchTextField.leftView?.tintColor = .white
Best solution I found was here
Changing the color of the icons in a UItextField inside a UISearchBar
(This solution uses the original UISearchBar's icon, no need to supply your own graphical asset)
Converted to Swift (Swift 3):
if let textFieldInsideSearchBar = self.searchBar.value(forKey: "searchField") as? UITextField,
let glassIconView = textFieldInsideSearchBar.leftView as? UIImageView {
//Magnifying glass
glassIconView.image = glassIconView.image?.withRenderingMode(.alwaysTemplate)
glassIconView.tintColor = .whiteColor
}
You can use a custom image of a white search icon, as the search bar will not modify your supplied image. To set a custom image, use this method. (Link to documentation.)
- (void)setImage:(UIImage *)iconImage
forSearchBarIcon:(UISearchBarIcon)icon
state:(UIControlState)state;
Example Code:
[searchBar setImage:[UIImage imageNamed:#"SearchIcon"]
forSearchBarIcon:UISearchBarIconSearch
state:UIControlStateNormal];
In Swift:
searchBar.setImage(UIImage(named: "SearchIcon"), for: .search, state: .normal)
This soultion worked for me on Xcode 8.2.1 in Swift 3.0. :
extension UISearchBar
{
func setPlaceholderTextColorTo(color: UIColor)
{
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = color
let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = color
}
func setMagnifyingGlassColorTo(color: UIColor)
{
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let glassIconView = textFieldInsideSearchBar?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = color
}
}
Usage example:
searchController.searchBar.setPlaceholderTextColorTo(color: mainColor)
searchController.searchBar.setMagnifyingGlassColorTo(color: mainColor)
Swift-3:
extension UISearchBar
{
func setMagnifyingGlassColorTo(color: UIColor)
{
// Search Icon
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let glassIconView = textFieldInsideSearchBar?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = color
}
func setClearButtonColorTo(color: UIColor)
{
// Clear Button
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let crossIconView = textFieldInsideSearchBar?.value(forKey: "clearButton") as? UIButton
crossIconView?.setImage(crossIconView?.currentImage?.withRenderingMode(.alwaysTemplate), for: .normal)
crossIconView?.tintColor = color
}
func setPlaceholderTextColorTo(color: UIColor)
{
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = color
let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = color
}
}
Call these extension method like this:
searchBarTextField.setMagnifyingGlassColorTo(color: yourColor)
searchBarTextField.setClearButtonColorTo(color: yourColor)
searchBarTextField.setPlaceholderTextColorTo(color: yourColor)
For just changing the color of the search icon, without altering the actual icon in Swift 3:
if let textField = self.searchBar.value(forKey: "searchField") as? UITextField,
let iconView = textField.leftView as? UIImageView {
iconView.image = iconView.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
iconView.tintColor = UIColor.red
}
Creates a result like so:
As per Federica's anwser....To do this in swift
var image: UIImage = UIImage(named: "search")!
self.searchBar.setImage(image, forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)
A solution for those using interface builder. You can add a User Defined Runtime Attribute to the UISearchBar:
searchField.leftView.tintColor of type Color
You can select the desired color of the icon, can be selected from your Color Assets library to support different colors for both light and dark mode.
Since iOS 13, we now have access to many standard system icons via SF Symbols. Also, if you want to have a unified colour scheme for your search bars so that they all look the same without having to duplicate code, you can use the Appearance workflow to change them all at once. For example:
let image = UIImage(systemName: "magnifyingglass")?.withTintColor(.white, renderingMode: .alwaysOriginal)
UISearchBar.appearance().setImage(image, for: .search, state: .normal)
This code sets all search bars in the app to use the standard magnifying glass icon, in white. You can use similar code to change the 'clear' button icon, the bookmark icon and the results list icon. You just need to change .search to the appropriate enumeration value and find the system name of the appropriate icon (which you can get from the free SF System app).
Another method that uses Appearance would be to set the tint colour of all views contained within a search view, though this may have unwanted effects in some cases (i.e. changing the colour of the text cursor):
UIView.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = .yellow
This will make the left icon and the text cursor yellow, though annoyingly not the 'clear' button for some reason. I prefer not to use this method as it may not be future-proof; Apple has a habit of changing things internally that can cause unexpected changes if you don't use their approved methods.
Following on from some of the answers here
If you would like to see and make the changes in storyboard first subclass UISearch bar and do as above.
However add the changes in a #IBInspectable variable and not forgetting the #IBDesignable at the top of the class and setting the searchbar subclass in the "Identity inspector"
I have added the full working subclass and code below for swift 3.0
Here you will be able to change the placeholder text, search text and magnifying glass
import UIKit
#IBDesignable
class CustomSearchBar: UISearchBar {
#IBInspectable var placeholderColor: UIColor? {
didSet {
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = placeholderColor
}
}
#IBInspectable var textColor: UIColor? {
didSet {
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = textColor
}
}
#IBInspectable var magnifyingGlassColor: UIColor? {
didSet {
if let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField,
let glassIconView = textFieldInsideSearchBar.leftView as? UIImageView {
//Magnifying glass
glassIconView.image = glassIconView.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
glassIconView.tintColor = magnifyingGlassColor
} }
}
}
Make sure that when you use the setImage API, pass an image with rendering mode of UIImageRenderingModeAlwaysTemplate. For example:
[self.searchBar setImage:[[UIImage imageNamed: #"icon-search"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
There are no adequate reasons to set your own custom image just for changing icon tint color. Don't forget about perfomance. And retrieving a value by a raw string key doesn't garantee that other coders can mistype usually calling app crashes. We're not perfect.
How about UISearchBar instance's property searchTextField (UISearchTextField)?
if let thatMysteriousLoop = yourSearchBar.searchTextField.leftView as? UIImageView {
thatMysteriousLoop.tintColor = anyColorYouWannaSet // <-- VoilĂ !
}
For swift 3
searchBar.setImage(UIImage(named: "location-icon-black"), for: .search, state: .normal)
My solution:
searchBar = UISearchBar()
searchBar.searchBarStyle = .minimal
searchBar.setTextColor(.white)
let textField = self.searchBar.getTextField()
let glassIconView = textField?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = .white
searchBar.showsCancelButton = true
extension UISearchBar {
func getTextField() -> UITextField? {
return self.value(forKey: "searchField") as? UITextField
}
func setTextColor(_ color: UIColor) {
let textField = getTextField()
textField?.textColor = color
}
}
I know it is an old post but since there is a Xamarin Bug on the dark mode and I was struggling for hours, I thought I share my pretty easy solution.
iOS- custom Renderer.
[assembly:ExportRenderer(typeof(SearchBar),typeof(YourProjectSearchbarRenderer))]
public class YourProjectSearchbarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
// iOS >13 -> Xamarin bug on darkmode,
// just shows the light icon...
this.Control.SetImageforSearchBarIcon(UIImage.FromFile("AddAnSearchIcon.ico"), UISearchBarIcon.Search, UIControlState.Normal);
}
}
}
if(IOS_7) {
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.backgroundImage = [UIImage imageWithColor:[UIColor redColor] cornerRadius:5.0f];
}

Resources