Replace font for every UILabel in the App - ios

I'm trying to change the font by make extension for UILabel
extension UILabel{
var defaultFont: UIFont? {
get { return self.font }
set {
let oldFontSize = self.font.pointSize
let oldFontName = self.font.fontName
let newFontName = newValue?.fontName
self.font = UIFont(name: newFontName!, size: oldFontSize)
}
}
}
then call
UILabel.appearance().defaultFont = UIFont.init(name: "My Font", size: 5)
But always self.font is nil
using xcode 10 swift 4.2
Edit:
Now, after changing swift version to Swift3 it works good, then the problem is in Swift4.
Are there a solution or Alternative way to do that ?

try this :
is appDelegate -> didFinishLaunch:
UILabel.appearance().font = UIFont("your font name", size: 15)

Standard way of doing is to create your custom UILabel class and use this class everywhere you want that default font. e.g,
class MyFontLabel: UILabel {
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
self.font = UIFont(name: "My Font", size: self.font.pointSize)
}
}

So while you technically can't override an instance variable, aka overriding UILabel's font variable won't work, you can extend UILabel.
public class CustomLabel: UILabel {
override public var font: UIFont! {
get { return super.font }
set {
super.font = UIFont(name: "Font-Name", size: super.font.pointSize)
}
}
}

I've found it most helpful to have add a style(as style: TypographyStyle) function in an extension to UILabel, where TypographyStyle is an enum I've defined that contains a bunch of style properties, including font. I also created a convenience init for UILabel that takes a case of TypographyStyle, and calls style(as:), so that the style will be automatically applied when the label is created.
extension UILabel {
convenience init(style: TypographyStyle) {
self.init()
self.style(as: style)
}
func style(as style: TypographyStyle) {
self.font = UIFont(name: style.fontName, size: style.fontSize)
}
}
enum TypographyStyle {
case body, h1, h2, h3
var font: UIFont {
switch self {
// here you can return different fonts for the different styles if you like
default:
return UIFont(name: "AvenirNext", size: 16)
}
}
}
// Usage
let label = UILabel(style: .body)

Put this on appDelegate in didFinishLaunchingWithOptions method:
UILabel.appearance().font = UIFont(name: "your font name", size: UILabel.appearance().font.pointSize)

Related

Changing UITextField Placeholder Color for ALL textfields in appDelegate

I know you can change the placeholder text with following code:
mailTextField.attributedPlaceholder = NSAttributedString(string: "Email", attributes: [NSAttributedString.Key.foregroundColor : UIColor.black])
unfortunately, I have a lot of textfields which should look all the same. So its very annoying to copy paste this code above for every textfield.
Today I found out you can change with appearance() in appDelegate the appearance of an UIElement if you want it to be always the same. The following code works perfectly fine for labels:
UILabel.appearance().textColor = Colors.greyLabel
But when I try to do this for textfield placeholders, it does not work.
Thanks for your help.
You can create custom class which is subclass of UITextField as
import Foundation
import UIKit
class CustomTextField:UITextField{
override init(frame: CGRect) {
super.init(frame: frame)
setProperties()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setProperties()
}
func setProperties(){
backgroundColor = UIColor.white
textAlignment = .left
textColor = .black
font = UIFont.systemFont(ofSize: 15)
borderStyle = .roundedRect
if let placeholder = self.placeholder {
self.attributedPlaceholder = NSAttributedString(string:placeholder, attributes: [NSAttributedString.Key.foregroundColor: UIColor.green])
}
}
}
If you are using storyboard then you can assign that custom class to UITextField
And programatically
var mailTextField = CustomTextField()
You can use ֿappearanceWhenContainedInInstancesOfClasses but it’s available up from iOS 9.
Example:
UILabel.appearanceWhenContainedInInstancesOfClasses([UITextField.self]).textColor = UIColor.redColor()’

Swift Setting subclass UIButton ButtonType

I have a simple subclass of UIButton
class IconButton: UIButton {
init(type: FontAwesomeStyle, icon: FontAwesome, color: UIColor = .black, size: CGFloat = 20) {
super.init(frame: CGRect.zero)
let iconAsText = String.fontAwesomeIcon(name: icon)
let iconText = NSMutableAttributedString(string: iconAsText, attributes: [
NSAttributedString.Key.font: UIFont.fontAwesome(ofSize: size, style: type)
])
setAttributedTitle(iconText, for: .normal)
setTitleColor(color, for: .normal)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The problem I am having is that I would like the button to have the behavior that system buttons have. Specifically when you press and hold the button, it changes color.
let button = UIButton(type: .system)
Since buttonType is a get only property of UIButton and UIButton.init(type: UIButton.ButtonType) is a convenience initailizer, I am not sure how to implement this a subclass.
Still not sure if its possible to replicate the .system button type in a subclass, but the solution for getting the behavior I wanted was the following:
class IconButton: UIButton {
override var isHighlighted: Bool {
willSet(newVal) {
if newVal != isHighlighted {
// newVal is true when the button is being held down
}
}
}
// Rest of class...
}

Changing Search Bar placeholder text colour in iOS 13

I'm trying to set colour for placeholder text inside UISearchbar. Right now I've following code. It doesn't set white colour to placeholder text on iOS 13. It works on iOS 12. It seems something is either broken or support has been removed in iOS 13?
I've searched a lot and tried few workarounds but doesn't work. I've also tried to set attributed text colour for textfield but that also doesn't change colour.
Is there a working solution for this?
class CustomSearchBar: UISearchBar {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.sizeToFit()
// Search text colour change
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = UIColor.white
// Search Placeholder text colour change
let placeHolderText = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
placeHolderText?.textColor = UIColor.white // doesn't work
}
}
viewDidLoad is too early
Put the code in viewDidAppear, viewDidLoad is too early. Then your placeholder should change to white
searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Enter Search Here", attributes: [NSAttributedString.Key.foregroundColor : UIColor.white])
In viewDidAppear
if iOS is higher than 13.0, use searchBar.searchTextField.attributedPlaceholder.
if iOS is lower than 13.0, use searchBar.value(forKey: "searchField") to access searchTextField
var searchBar = UISearchBar()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 13.0, *) {
searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Enter Search Here", attributes: [NSAttributedString.Key.foregroundColor : UIColor.white])
} else {
if let searchField = searchBar.value(forKey: "searchField") as? UITextField {
searchField.attributedPlaceholder = NSAttributedString(string: "Enter Search Here", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white2])
}
}
}
Try this:
var searchBar: UISearchBar!
if let textfield = searchBar.value(forKey: "searchField") as? UITextField {
textfield.attributedPlaceholder = NSAttributedString(string: textfield.placeholder ?? "", attributes: [NSAttributedString.Key.foregroundColor : UIColor.white])
}
Please add this extension and try this !
extension UISearchBar{
var placeholderLabel: UILabel? { return value(forKey: "placeholderLabel") as? UILabel }
func setPlaceholder(textColor: UIColor) {
guard let placeholderLabel = placeholderLabel else { return }
let label = Label(label: placeholderLabel, textColor: textColor)
placeholderLabel.removeFromSuperview() // To remove existing label. Otherwise it will overwrite it if called multiple times.
setValue(label, forKey: "placeholderLabel")
}
}
private extension UITextField {
private class Label: UILabel {
private var _textColor = UIColor.lightGray
override var textColor: UIColor! {
set { super.textColor = _textColor }
get { return _textColor }
}
init(label: UILabel, textColor: UIColor = .lightGray) {
_textColor = textColor
super.init(frame: label.frame)
self.text = label.text
self.font = label.font
}
required init?(coder: NSCoder) { super.init(coder: coder) }
}
Usage
yourSearchBarObject.setPlaceholder(textColor: .red)
You need to style everything in viewDidAppear

Set different font as per title and subtitle in UIlabel IBDesignable

I had created the custom class for uilabel with below code:
#IBDesignable
public class CustomUILabel: UILabel {
public override func awakeFromNib() {
super.awakeFromNib()
configureLabel()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
configureLabel()
}
func configureLabel() {
textColor = .white
font = UIFont(name: Constants.regularFontName, size: 14)
}
}
This help me to set the font through out the application.But i wanted to create different bold font type for title and regular font for subtitle.
Is this possible only with one file ?
Or i need to create different Extension for that type of UIlabel
You could for example add a custom style property like this:
#IBDesignable
public class CustomUILabel: UILabel {
enum CustomUILabelStyle {
case title, subtitle
var font: UIFont? {
switch self {
case .title:
return UIFont(name: Constants.boldFontName, size: 14)
case .subtitle:
return UIFont(name: Constants.regularFontName, size: 14)
}
}
var textColor: UIColor {
switch self {
// add cases if you want different colors for different styles
default: return .white
}
}
}
var style: CustomUILabelStyle = .title {
didSet {
// update the label's properties after changing the style
if style != oldValue {
configureLabel()
}
}
}
public override func awakeFromNib() {
super.awakeFromNib()
configureLabel()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
configureLabel()
}
func configureLabel() {
font = style.font
textColor = style.textColor
}
}
You use it like this:
let label = CustomUILabel()
label.style = .title
// label.style = .subtitle

Custom UITableViewCell labels

I'm trying to create a custom UITableViewCell with 3 labels, in a similar style to the subtitle style, but with a label on the right, too. I've got 2 issues, so far:
When creating the labels on the left, I was using a constant 16 offset, but have since found this is incorrect. The separator inset returns 15 (self.separatorInset.left), but iPad the labels seem to be 22.5 from the left. I'll have to do this in code, but is checking for the iPad UI idiom and multiplying by 1.5 the correct way of doing this?
The second issue is that I am using dynamic font sizes: Body for the main label and Caption 1 for the subtitle. However, this creates labels with font size 17 and 12 respectively, while the system cell's labels are 16 and 11. I've got a custom UILabel that tries to ensure system font size changes are respected. Should I make the font size 1 smaller in this class?
class DynamicFontLabel: UILabel {
var fontStyle: String?
convenience override init() {
self.init(fontStyle: UIFontTextStyleBody)
}
init(fontStyle: String) {
super.init()
self.font = UIFont.preferredFontForTextStyle(fontStyle)
self.setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
func setup() {
// Ensure the text color is correct, as per the UILabel appearance
self.textColor = UILabel.appearance().textColor
self.fontStyle = self.currentFontStyle()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateFontSize", name: UIContentSizeCategoryDidChangeNotification, object: nil)
self.numberOfLines = 0
self.lineBreakMode = NSLineBreakMode.ByWordWrapping
}
func currentFontStyle() -> String {
if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)) {
return UIFontTextStyleHeadline
} else if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleBody)) {
return UIFontTextStyleBody
} else if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleCaption1)) {
return UIFontTextStyleCaption1
} else if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleCaption2)) {
return UIFontTextStyleCaption2
} else if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote)) {
return UIFontTextStyleFootnote
} else if self.font.isEqual(UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)) {
return UIFontTextStyleSubheadline
}
return UIFontTextStyleBody
}
func updateFontSize() {
if let fontStyle = self.fontStyle {
self.font = UIFont.preferredFontForTextStyle(fontStyle)
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}

Resources