Subclassing UINavigationBar in Swift - ios

I'm trying to create a custom UINavigationBar class and then use the Storyboard to set it as the class of my UINavigationController's NavigationBar.
Here's the code of my UINavigationBar class:
class CustomNavBar: UINavigationBar {
override func drawRect(rect: CGRect) {
super.drawRect(rect)
// Drawing code
self.backgroundColor = UIColor.orangeColor()
let myLabel = UILabel(frame: CGRect(x: 0, y: 4, width: 600, height: 36))
myLabel.backgroundColor = UIColor.purpleColor()
myLabel.textColor = UIColor.yellowColor()
myLabel.text = "Custom NavBar!"
self.addSubview(myLabel)
}
}
Then, in Interface Builder, I use the Identity Inspector to set this as the class of the NavigationBar of my UINavigationController.
When I run the App - it freezes. It hangs up on the LaunchScreen.xib and doesn't do anything.
Why is doing that? What's the right way to go about doing this?

On Swift:
File-New-File- iOS Source - Cocoa Touch class- Select Subclass of : UINavigationBar and Name it - CustomNavigationBar.
class CustomNavigationBar: UINavigationBar {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.redColor()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override func drawRect(rect: CGRect) {
}
}

Related

Custom UIButton class does not show title

I have created a custom UIButton class. But the title does not show up. I only get the background color and the rounded corners. But the title is not visible.
Also when I run it in simulator, iOS 13+, its showing the title white. But when I run in my device i.e. iOS 12.4, its not working.
Here is my code:
public class CornerButton : UIButton {
public override init(frame: CGRect) {
super.init(frame: frame)
setup()
self.layoutIfNeeded()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
self.layoutIfNeeded()
}
func setup() {
self.titleLabel?.font = UIFont(name: "Poppins-SemiBold", size: 12)
self.backgroundColor = UIColor(named: "BarColor")
self.setTitleColor(.white, for: .normal) // this line is not working
self.clipsToBounds = true
}
public override func layoutSubviews() {
self.roundCorners(corners: [.topRight,.bottomLeft], radius: 10)
}
}
You need to call super.layoutSubviews()
public override func layoutSubviews() {
super.layoutSubviews()
self.roundCorners(corners: [.topRight,.bottomLeft], radius: 10)
}
BTW here you don't need layoutSubviews as you use it when you need to make something that depends on the actual measured bounds of the view and as you set a static radius you can omit it

Rounded UIButton - iPad size

I have custom UIButton to have rounded edges
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = self.bounds.width * 0.5
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.cornerRadius = self.bounds.width * 0.5
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
}
Now I am using this "RoundedButton" (size of 110, 110) in a UIViewcontroller's XIB file and the constraints are set to maintain the aspect ratio w.r.t UIViewcontrollers view.
The button looks rounded in iPhone simulators but the button is NOT rounded in iPad simulator. When I set the layer.cornerRadius property in viewDidAppear then the button is rounded in iPad simulator.
Please see images
I am looking for an alternative solution than re-defining layer corner radius again in viewDidappear.
Thanks
override method layoutSubviews like this:
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width * 0.5
}
Also you can now remove cornerRadius line from init
For more go to documentation of UIView: https://developer.apple.com/documentation/uikit/uiview/1622482-layoutsubviews
Override layoutSubviews function:
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.backgroundColor = UIColor(patternImage: UIImage(named: "map.png")!)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width * 0.5
}
}
import UIKit
class RoundedButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setTitleColor(UIColor.white, for: UIControlState.normal)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.bounds.width / 2
}
}
I have also create a code sample for you. RoundedButton

Custom UITextField class only applied to first text field

I have made my first custom class in Swift and I want to use it for the text fields in my app. The problem is that it only works for the first textfield in the view controller, the class is not applied to the second one (the second one has no rounded corners, default placeholder color etc.). I have double checked that the right "custom class" is set in the storyboard for both textfields. Why isn't the class applied to both fields? Seems like a thing with a simple solution but I haven't found any...
Here is the class:
import UIKit
class RoundedUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.setAttributes()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setAttributes() {
self.layer.cornerRadius = 20.0
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: self.frame.height))
self.leftView = paddingView
self.leftViewMode = UITextFieldViewMode.always
self.textColor = UIColor.white
self.alpha = 0.7
let str = NSAttributedString(string: (self.placeholder)!, attributes: [NSForegroundColorAttributeName:UIColor.white])
self.attributedPlaceholder = str
}
}
Here is the view controller code:
class LogInViewController: UIViewController {
#IBOutlet weak var password: RoundedUITextField!
#IBOutlet weak var userName: RoundedUITextField!
override func viewDidLoad() {
super.viewDidLoad()
userName.setAttributes()
// Do any additional setup after loading the view.
}
I discovered now that the problem lies in the "setAttributes", I thought the attributes where set in the class but they're actually only set in viewDidLoad for one of them (I put it there in the beginning and forgot to remove it)... I want this to be done in the "init" of the class for all of the fields...
Put your self.setAttributes() in your awakeFromNib method and remove it from init(frame: CGRect)
override func awakeFromNib() {
super.awakeFromNib()
self.setAttributes()
}
your custom class code will be like this
import UIKit
class RoundedUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.setAttributes()
}
func setAttributes() {
self.layer.cornerRadius = 20.0
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: self.frame.height))
self.leftView = paddingView
self.leftViewMode = UITextFieldViewMode.always
self.textColor = UIColor.white
self.alpha = 0.7
let str = NSAttributedString(string: (self.placeholder)!, attributes: [NSForegroundColorAttributeName:UIColor.white])
self.attributedPlaceholder = str
}
}
Hope this helps

Title not showing for custom UIButton class

I have created a custom UIButton class which features a round frame. The problem is although I set up the title property of each button from the storyboard they are not showing. I end up with round buttons with no titles showing inside them. I am trying to do a keypad like the one in default iOS passcode screen. My main view background color is not white and I am not using any background images for the buttons. Here is my code for the custom UIButton class.
import Foundation
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFontOfSize(33.0)
self.titleLabel?.textColor = UIColor.whiteColor()
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.whiteColor().CGColor
self.layer.borderWidth = 2.0
}
}
Had same issue, this answer worked for me: Custom UIButton subclass not displaying title
Add super.layoutSubviews() after you override the function.
Have you set your UIButton's class as your custom class in storyboard??
Try to put all the things in init method and check.
import Foundation
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFontOfSize(33.0)
self.titleLabel?.textColor = UIColor.whiteColor()
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.whiteColor().CGColor
self.layer.borderWidth = 2.0
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Here is working code for Swift 4
import UIKit
class MyOwnButton: UIButton {
override init(frame: CGRect){
super.init(frame: frame)
commonSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonSetup()
}
private func commonSetup() {
self.clipsToBounds = true
self.titleLabel?.font = UIFont.systemFont(ofSize: 33.0)
self.titleLabel?.textColor = UIColor.white
self.layer.cornerRadius = self.frame.size.width / 2.0
self.layer.borderColor = UIColor.white.cgColor
self.layer.borderWidth = 2.0
}
}
After setting the title of the button, simply:
[button sizeToFit];

Is it possible to add a UIView as UINavigationBar's background

I'm trying to create a specific background to a UINavigationBar, but I don't want to use images or solid color, I have a custom UIView that i've created and in it's drawRect method I'm drawing some stuff, I want this to be the UINavigationBar's background.
Is it possible?
This is my custom view:
class GradientColorView : UIView {
var colors : NSArray = NSArray() {
didSet {
setNeedsDisplay()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
var topRect : CGRect = CGRectMake(0, 0, rect.size.width, rect.size.height / 2.0)
var firstColor : UIColor = self.colors[0] as! UIColor
firstColor.setFill()
UIRectFill(topRect)
var bottomRect : CGRect = CGRectMake(0, rect.size.height/2.0, rect.size.width, rect.size.height/2.0)
var secondColor : UIColor = self.colors[1] as! UIColor
secondColor.setFill()
UIRectFill(bottomRect)
}
}
And in Swift of course :)
So i've found the answer to my question, what I did is created a UINavigationBar subclass called CustomNavigationBar and override init method like that:
class CustomNavigationBar: UINavigationBar {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.someColor()
let view : UIView = UIView(frame: CGRectMake(0, 20, frame.size.width, 44))
self.addSubview(view)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
}
}
Then I've added this method on the UIViewController that holds the UINavigationBar:
func styleCustomNavigationBar() {
self.navigationController?.setNavigationBarHidden(true, animated: false)
var navigationBar : CustomNavigationBar = CustomNavigationBar(frame: CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.0))
var navigationItem : UINavigationItem = UINavigationItem()
var backButton : UIBarButtonItem = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "backButtonDidClicked")
navigationItem.leftBarButtonItem = backButton
navigationBar.items = [navigationItem]
self.view.addSubview(navigationBar)
}
I used this and question and this website to reach solution.
Enjoy!

Resources