In my code, I have created a custom button (i.e subclass of UIButton), But I am unable to set the font to the button. Have observed that, If I am using self.titleLabel?.text = title it works fine but whenever I am using method self.setTitle(title, for: .normal) font get reset to system font. I need that font for all the states of the button so I have to use the function setTitle. My custom button code is as follows
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
styleButton()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
styleButton()
}
func styleButton(title: String = "button", font: UIFont = .customFont16) {
self.setTitle(title, for: .normal)
self.backgroundColor = UIColor.yellow
titleLabel?.font = font
}
}
You can add a variable for setting font in a custom class. Then set the font from the viewController.
var titleFont: UIFont = UIFont.preferredFont(forTextStyle: .footnote) {
didSet {
titleLabel?.font = titleFont
}
}
Add the above code into your custom class and access it in the viewController like this.
#IBOutlet weak var roundButton: RoundedButton!
override func viewDidLoad() {
super.viewDidLoad()
roundButton.titleFont = .caption1
}
Related
I am working on creating my own framework with common screens and functions. I am stuck at achieving the following:
I have 3 screens inside the framework and which are having UILabel and UITextField.
I want to apply the font to all UILabel and UITextField inside the framework which is used throughout the application.
Example: If I am using "Kingthings_Trypewriter_2.ttf" in my
application then by writing this line should change the font of all
respective UILabels and UITextFields.
UILabel.appearance().font = UIFont(name: "Kingthings_Trypewriter_2", size: 20)
UITextView.appearance().font = UIFont(name: "Kingthings_Trypewriter_2", size: 20)
Still, by using the above code it is working for labels and UITextFields of application but not with labels and UITextFields of Frameworks.
Any help will be appreciated.
Declare a specific class and use that custom label or textview for entire framework.
class FrameWorkLabel: UILabel{
var frameWorkFont: UIFont?
private func setupViews(){
font = frameWorkFont ?? UIFont.frameWorkFont
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
}
class FrameWorkTextField: UITextField{
var frameWorkFont: UIFont?
private func setupViews(){
font = frameWorkFont ?? UIFont.frameWorkFont
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
}
extension UIFont{
static let frameWorkFont = UIFont.systemFont(ofSize: 18)
}
Use the instance of label or textfield wherever you want in the project.
#IBOutlet weak var label : FrameWorkLabel!
//or
let label1 = FrameWorkLabel()
#IBOutlet weak var textField : FrameWorkTextField!
let textField1 = FrameWorkTextField()
I have controllingView, that needs to change a property in presentingView. They are both in the same ViewController.
I can let them communicate by making presentingView delegate of controllingView. But it would be far more elegant and flexible, if I could just change the property directly (since
I need to change the presentingView's property's property actually)
I have seen it done in this question: Accessing protocol property in Swift class.
But in controllingView, calling delegate.propertyINeedToChange is nil.
How do I change a delegate's property from the delegating object?
Here is the code:
class MainViewController : UIViewController {
var controllingView = ControllingView()
let presentingView = PresentingView()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
view.addSubview(controllingView)
view.addSubview(presentingView)
self.view = view
controllingView.delegate = presentingView
}
}
class ControllingView: UIView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
//ControlsView Setup
self.backgroundColor = UIColor(displayP3Red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0)
setupViews()
}
let testSLDR = UISlider()
var delegate: ControlsViewDelegate?
func setupViews() {
self.addSubview(testSLDR)
testSLDR.addTarget(self, action: #selector(testSLDRchanged), for: .valueChanged)
}
#objc func testSLDRchanged() {
delegate?.button?.backgroundColor = UIColor.red
}
}
class PresentingView: UIView, ControlsViewDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
let button = Button()
self.addSubview(button)
}
var button: Button?
}
protocol ControlsViewDelegate {
var button: Button? { get set }
}
class Button: UIButton { ... }
As the views are initialized in the same view controller you don't need protocol / delegate
Delete the protocol and the associated code
In ControllingView declare a weak Button property
weak var presentingButton : Button?
Replace the line to set the delegate with a line to assign the button of PresentingView to the presentingButton property
controllingView.delegate = presentingView
controllingView.presentingButton = presentingView.button
In the action change the color
#objc func testSLDRchanged() {
presentingButton?.backgroundColor = UIColor.red
}
I have a button that repeats throughout my app, so I created a subclass to avoid having to set all the basic properties every time.
I am able to set the background colour, the text colour, round the corners.
However, things fall apart when I try to set a default title - something other than "Button".
In Interface Builder it ignores the title, but it also then ignores the font colour, which works when I don't set the title.
If I run the app, it all looks fine, but one major point of using Interface Builder is to save the step of constantly running the app to check basic UI layout.
Here is the subclass.
Note that if you comment out the 2 setTitle lines, the button shows the correct text colour (white).
import UIKit
#IBDesignable class ContinueButton: UIButton {
#IBInspectable var titleColour: UIColor = .white {
didSet {
setTitleColor(titleColour, for: .normal)
}
}
#IBInspectable var bgColour: UIColor = UIColor.gray {
didSet {
backgroundColor = bgColour
}
}
#IBInspectable var buttonTitle: String = "Continue" {
didSet {
setTitle(buttonTitle, for: .normal)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setAttributes()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setAttributes()
}
public func setAttributes() {
setTitleColor(titleColour, for: .normal)
backgroundColor = bgColour
setTitle(buttonTitle, for: .normal)
}
override public func layoutSubviews() {
super.layoutSubviews()
setAttributes()
layer.cornerRadius = 0.5 * bounds.size.height
clipsToBounds = true
}
}
ps, My main objective is to create a reusable custom button that takes care of setting a bunch of defaults. If there's a better way to achieve that, I'd be very happy to hear that - especially if it could be done visually rather than through code.
Thanks for any advice you can give,
-Nico
Just override prepareForInterfaceBuilder() and add setAttributes().
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setAttributes()
}
The tintColor property will do the trick.
button.tintColor = UIColor.red
but to make sure to override the prepareForInterfaceBuilder()
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
button.tintColor = UIColor.red
}
I created a customTableViewFooter programmatically like this:
import UIKit
class CustomFooterView: UIView {
let myLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightMedium)
label.textColor = UIColor.black
label.numberOfLines = 1
label.text = "Blah blah blah"
label.textAlignment = .center
return label
}()
let mySwitch: UISwitch = {
let mySwitch = UISwitch()
mySwitch.addTarget(self, action: #selector(switchChanged), for: .valueChanged)
return mySwitch
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
self.layout()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
self.setup()
self.layout()
}
private func setup() {
self.addSubview(myLabel)
self.addSubview(mySwitch)
}
private func layout() {
anonymousLabel.constrainCenterVertically()
anonymousLabel.constrainCenterHorizontally()
anonSwitch.constrainCenterVertically()
anonSwitch.constrainTrailing(at: 20)
}
func switchChanged() {
print("hello")
}
}
Inside my class which implements the UITableView, I add this footer programmatically:
class MyViewController: UIViewController {
var footerView = CustomFooterView()
override func viewDidLoad() {
super.viewDidLoad()
addFooter()
}
func addFooter() {
tableView.tableFooterView = footerView
}
...
}
At the moment, I have the method: switchChanged inside the class where I declare my UISwitch, and what I would like to do, is move this method to my ViewController, so the that the UISwitch, when selected by the user, calls a method inside my ViewController. How would I do this?
This should work (as already suggested in a comment)
footerView.mySwitch.addTarget(self, action: #selector(aSelector), for: .valueChanged)
I am subclassing UIStepper and I'd like to apply some custom styling. I am doing using following method…
func setupStepper() {
let incrementImageFromFile : UIImage = UIImage(named: "plusSymbol")!
let incrementImage : UIImage = incrementImageFromFile.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
let decrementImageFromFile : UIImage = UIImage(named: "minusSymbol")!
let decrementImage : UIImage = decrementImageFromFile.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
tintColor = UIColor.clear()
setDecrementImage(decrementImage, for: [])
setIncrementImage(incrementImage, for: [])
}
I tried hooking this styling into the following methods but it doesn't get called.
class RoundedStepper: UIStepper {
override init(frame: CGRect) {
super.init(frame: frame)
setupStepper()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupStepper()
}
override func awakeFromNib() {
setupStepper()
}
…
I am using this custom stepper subclass in a Storyboard. Why doesn't setupStepper() get called? Where is the correct place to add this styling method?