问题
I know that for elements of classes UIButton
and UIBarButtonItem
they automatically assume window.tintColor
as the main colour, which results of an immediate change in case I set a new tintColor to window at any time in the app.
I was wondering if there is any way to make UILabel
elements to follow the same pattern, where once created they automatically assumer its default colour as window.tintColor
and if changing window.tintColor
at any time within my app runtime would also result in changing the UILabel
tintColour automatically?
I hope that makes sense.
回答1:
UILabels
are a subclass of UIView
, so when you are running in iOS 7 they will have a tintColor
property and will inherit that color from their parent view if their tint color is set to nil
(which is default).
From Apple's Documentation:
By default, a view’s tint color is nil, which means that the view uses its parent’s tint. It also means that when you ask a view for its tint color, it always returns a color value, even if you haven’t set one.
However, you also ask "if changing window.tintColor at any time within my app runtime would also result in changing the UILabel tintColour automatically?" Apple advises you to not change the tint color when items are on screen:
In general, it’s best to change a view’s tint color while the view is offscreen.
I would guess this is because there is no guarentee that all the various UI elements will detect the tintColor change and update their visible views. However, the UIView documentation suggests a workaround if you want to update tintColor
while your UILables
are on screen:
To refresh subview rendering when this property changes, override the tintColorDidChange method.
So just make sure to call tintColorDidChange
on any views currently on screen whose tint color should update when the tintColor
of their parent view changes.
But why don't your UILabel
's update their color?
So the above helps you set and update your various tintColor
's, but you're not seeing any effect - why?
Well that has to do with what Apple designed Tint to indicate. From the Human Interface Guidelines:
color gives users a strong visual indicator of interactivity
Apple got rid of borders and gradients around interactive elements and replaced them with color - specifically tintColor
. The whole idea behind tintColor
is that things users can tap on get it, and things they can't tap on don't.
UILabel
is not an interactive element - it is a text description - and so Apple will let you set a tintColor
on it (as any UIView
has a tintColor
) but setting that tintColor
will not change how it is drawn.
So what should you do? First, be aware that making more than just buttons take on the tint color could be a poor UI choice for your app - iOS 7 users and Apple app reviewers both will be expecting those rules to be followed.
So are you forced to keep your UILabel
free from color then?
No - especially if you do things "right". Apple explains:
In a content area, add a button border or background only if necessary. Buttons in bars, action sheets, and alerts don’t need borders because users know that most of the items in these areas are interactive. In a content area, on the other hand, a button might need a border or a background to distinguish it from the rest of the content.
I would suggest you consider the UI of your app. If you really want your non-intereactive elements to have the same tintColor
as your interactive elements, then make sure you use something more, like a border or background color, so your users (and Apple app reviewers) know what is clickable and what is not.
As to how you should update the colors, you can either manually set the textColor
property to be whatever color you want, or you'll need to make your own subclass of UILabel
that overrides - (void)tintColorDidChange
to update the textColor
property when notifications are sent out - allowing you to have a UILabel
whose text updates to match the tintColor
of its parent.
I hope this helps!
回答2:
Found above explanation to be helpful - particularly the pointer to tintColorDidChange(). However, getting it to work out right didn't work at first, but finally came up with a code example that does. Basically, I had a tableView with cells containing images and labels. The images would update with a change in tintColor, but not the labels - which didn't look right. Better for either both to change or neither change. The code below is for the cell in the tableView. This was written with Swift 4.2.
//
// ImageLabelCell.swift
// -- provides an example of changing "tintColor" of UILabel to behave like other elements.
// -- made problem a bit more complex by having a "selected" cell be in inverse colors - so also deal with background.
//
import UIKit
enum CellTypes: Int, CaseIterable { case cell1, cell2, cell3, cell4
// This type provides a demonstration of a way to associate different titles and images to populate the UILabel and UIImageView in the cell.
var title: String {
return "\(self)".uppercased()
}
var imageName: String {
return "\(self)"
}
}
class ImageLabelCell: UITableViewCell {
@IBOutlet weak var lblString: UILabel?
@IBOutlet weak var imgView: UIImageView!
fileprivate var type = CellTypes.cell1
fileprivate var cellSelected = false
}
extension ImageLabelCell {
func getFgBgColors() -> (UIColor, UIColor) { // get foreground, background colors
let white = UIColor.white
var useTint = UIColor.blue // Use your app color here. Just ensures useTint is not nil.
if let tint = tintColor {
useTint = tint
}
if cellSelected {
return (white, useTint) // Selected cell is white on colored background
} else {
return (useTint, white) // Unselected cell is colored on white background
}
}
func configureCell(type: CellTypes, andSelected selected: Bool) {
// Save properties we may use again later
self.type = type
self.cellSelected = selected
// Set label text and image
lblString?.text = type.title
imgView.image = UIImage(named: type.imageName)
// Set colors
let (fgColor, bgColor) = getFgBgColors()
imgView.tintColor = fgColor
self.contentView.backgroundColor = bgColor
lblString?.textColor = fgColor
}
override func tintColorDidChange() {
// This gets called when the program tint color changes to gray (or back again) such as when popups appear/disappear.
let (fgColor, bgColor) = getFgBgColors()
// NOTE: need to set text color and background color. Imageview can take care of itself.
lblString?.textColor = fgColor
self.contentView.backgroundColor = bgColor
}
}
来源:https://stackoverflow.com/questions/19121313/ios7-uilabel-to-adopt-same-tintcolor-as-window