UILabels as part of UIView subclass do not initiate - ios

So, I have a subclass of UIView that I want to contain two custom UILabels. The subclass of my UIView initialises as "it should", however, the UILabels do not (I have tried with ordinary UILabels as well, but that does not work either.). The is no trace of any print statement and they are not displayed. They do work fine on their own, when I put one directly onto the storyboard.
I do not know were to turn, nor what is wrong. I have scoured the internet for days now. Please help this beginner...
class MainscreenButton: UIView {
#IBOutlet var icon: LAUILabel!
#IBOutlet var info: LAUILabel!
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)!
print("mainscreenbutton requiredinit")
}
override init(frame: CGRect) {
super.init(frame: frame)
print("mainscreenbutton frameinit")
}
}

Well.
they should initialize.. you just need to give them a frame/bounds/position. IBOutlet implies storyboard or NIB, so make sure that you set the class in the storyboard or nib and connect the IBOutlet. then give the labels constraints + text and they should appear.
if you wanted to do something like var icon = LAUILabel() and then in the initializers do like icon.frame = CGRect(... blah whatever) or programmatic constraints for autolayout that should work too
Do note that in my code though I have this as the storyboard/nib initializer
required init?(coder aDecoder: NSCoder) {
}
not sure if its just not picking up on it bc of slightly different method signature
you also many need to call label.layoutIfNeeded() if you don't give them explicit width constraints (maybe you only give it an x). Because it'll be initialized with a 0 width if theres no text and no width or no leading/trailing x constraints.

I'm not sure why you are doing UIView as button but if u want to do like that just flow this:
1) Create UILabel Custom class
class LAUILabel: UILabel {
//you can even define some params like #IBOutlet images ...
override init(frame: CGRect) {
super.init(frame: frame)
updateUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
updateUI()
}
private func updateUI() {
backgroundColor = .red
textColor = .green
numberOfLines = 1
textAlignment = .center
}
}
2) Create your MainscreenButton
class MainscreenButton: UIView {
#IBOutlet weak var icon: LAUILabel!
#IBOutlet weak var info: LAUILabel!
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)!
print("mainscreenbutton requiredinit")
}
override init(frame: CGRect) {
super.init(frame: frame)
print("mainscreenbutton frameinit")
}
}
3) Connect your UI with your custom classes
you will go to storyboard or Xib files and drag a view go to Identity Inspector then insert the name of your class 'MainscreenButton' in the custom class after that drag UILabels inside that view and change the custom class from the identity inspector like before 'LAUILabel' then link the the labels with the corespondent UI its should work.
4) Otherwise you can create the label without storyboard like this:
class MainscreenView: UIView {
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)!
print("mainscreenbutton requiredinit")
let icon = LAUILabel(frame: CGRect(origin: CGPoint(x: 100, y: 50), size: CGSize.zero))
icon.text = "icon"
icon.sizeToFit()
addSubview(icon)
let info = LAUILabel(frame: CGRect(origin: CGPoint(x: 200, y: 50), size: CGSize.zero))
info.text = "info"
info.sizeToFit()
addSubview(info)
}
override init(frame: CGRect) {
super.init(frame: frame)
print("mainscreenbutton frameinit")
}
}

Related

SWIFT passing parameter from VC to UIView drives me nuts

I am trying to get this done since yesterday, but no approach was successful. While I have learned a lot, some fundamentals still seem to be missing.
I have a view controller that shall contain several subviews in a stack. Each subview shall use the same UIView class in a separate swift file. However, for each subview I want to pass a position ID to the UIView class. The controller and the subviews are created with the storyboard.
So my latest and best approach is
class SpatialViewController: UIViewController {
#IBOutlet var redSquare: SpatialProblemView!
#IBOutlet var blueSquare: SpatialProblemView!
override func viewDidLoad() {
super.viewDidLoad()
redSquare = SpatialProblemView(subviewName: "red")
blueSquare = SpatialProblemView(subviewName: "blue")
// redSquare.subviewName = "red"
self.view.addSubview(redSquare)
}
}
and
class SpatialProblemView: UIView {
var subviewName: String
init(subviewName: String){
self.subviewName = subviewName
super.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I have also tried to code the UIView with this
required init(subviewName: String) {
super.init(frame: .zero)
self.subviewName = subviewName
self.setup()
}
required override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
func setup() {
if subviewName == "red" {
print ("red")
}
}
but that seem further apart from a running code. With the upper UIView definition I receive the error Fatal error: init(coder:) has not been implemented in the console and Property 'self.subviewName' not initialized at super.init call inline within the editor. Both relate to
super.init(coder: aDecoder)
I have looked for other posts here with this error message, but none I saw helped me. Any help is highly appreciated :-)
Try to make it optional
var subviewName: String?
and if you make them as outlets then you shouldn't assign a new instance here
SpatialProblemView(subviewName: "red")
just assign the property
redSquare.subviewName = "red"

Custom UIView Implemenation

I have customView called BaseView which has a contentView, In the contentView I am adding all other subviews(UILabel, UIButton, etc) in the override init(frame: CGRect) method.
Now I have 10 subclasses of my BaseView, which also overriding init(frame: CGRect) and calling base class init(frame: CGRect) method.
Here all my subclasses looks similar UI to its BaseView, Now there is one subclass of BaseView doesn't want some of the UI Elements in this base class, but I still need to call superview init(frame: CGRect). How do I change the code without affecting other classes?
Class BaseView: UIView {
let contentView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
let lbl1 = UILabel()
contentView.addSubView(lbl1)
let lbl2 = UILabel()
contentView.addSubView(lbl2)
self.addSubView(contentView)
}
Class subView1: BaseView {
override init(frame: CGRect) {
super.init(frame: frame)
// This class will show lbl1, lbl2 and lbl3 in the contentview
let lbl3 = UILabel()
contentView.addSubView(lbl3) // this contentview is BaseView's ContentView
}
// Similarly I have around 10 Subclasses of BaseView which is adding some UI Element to
baseview's contentView
// Question here is, below I am going to create another subclass of BaseView, But I don't
want to show lbl1 and lbl2 which is created in my BaseView's contentview
Class myView: BaseView {
// this class should not show the base class uilement lbl1 and lbl2, It should show only
lbl4 which is created by this class only
override init(frame: CGRect) {
super.init(frame: frame)
let lbl4 = UILabel()
contentView.addSubView(lbl4) // this contentview is BaseView's ContentView
}
How do I change the code without affecting other classes?
You don't. A different approach is needed. Three options are:
Don't derive the view in question from BaseView, and just reproduce whatever BaseView functionality you need.
Continue to derive from BaseView, and hide or remove the elements you don't need after BaseView's initialization method. The success of this plan will depend on how tolerant BaseView is when elements it expects are missing.
Refactor the functionality in BaseView into some new class that has the behavior that's common to all your views, and have your one outlier view and BaseView each descend from that new class.
Here is a different approach to implementing the required functionality.
Create a parent class with a content view where you want to show the content.
class SuperView: UIView {
let contentView = UIView()
override init(frame: CGRect) {
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("init(coder:) has not been implemented")
}
}
Inherit BaseView class from SuperView class and you can inherit other classes from BaseView class.
class BaseView: SuperView {
override init(frame: CGRect) {
super.init(frame: .zero)
contentView.addSubview(UILabel()) // UILabel 1
contentView.addSubview(UILabel()) // UILabel 2
self.addSubview(contentView)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("init(coder:) has not been implemented")
}
}
Inherit SubView class from SuperView class to add different properties and functions that you want. Here you don't need to inherit from BaseView class.
class SubView: SuperView {
override init(frame: CGRect) {
super.init(frame: .zero)
contentView.addSubview(UILabel()) // UILabel 3
self.addSubview(contentView)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("init(coder:) has not been implemented")
}
}
I hope it will help you to implement the required functionality as you want.

How to apply custom font to all Labels, UITextFields and UIButtons in entire framework?

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()

#IBDesignable not showing background color in IB

I have a UIView as below:
import UIKit
#IBDesignable
class CHRAlertView: UIView {
#IBOutlet var icon:UILabel!
#IBOutlet var alertText:UITextView!
override init(frame: CGRect) {
super.init(frame: frame)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initialize()
}
private func initialize(){
self.backgroundColor = UIColor.green
}
}
Based on how #IBDesignable works, this should show up in IB with a green background, but I get the clear color like this:
Why is this not functioning as expected? I need the background color to show in IB based on the defaults set in my #IBDesignable.
Since backgroundColor is an IB property not created via #IBInspectable, it always seems to overwrite whatever is in the init or draw methods. Meaning, if it is "default" in IB, it causes it to be overwritten with nil. However, if set in the prepareForInterfaceBuilder method backgroundColor works and shows in IB. So, the backgroundColor, it can be reasonably assumed, must be set at runtime. To do this I have the below:
//------------------
//Setup and initialization
//------------------
override init(frame: CGRect) {
super.init(frame: frame)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initialize()
}
//Setups content, styles, and defaults for the view
private func initialize(){
self.staticContent()
self.initStyle()
}
//Sets static content for the view
private func staticContent() {
}
//Styles the view's colors, borders, etc at initialization
private func initStyle(){
}
//Styles the view for variables that must be set at runtime
private func runtimeStyle(){
if self.backgroundColor == nil {
self.backgroundColor = UIColor.green
}
}
override func prepareForInterfaceBuilder() {
self.runtimeStyle()
}
override func awakeFromNib() {
super.awakeFromNib()
self.runtimeStyle()
}
This defaults the backgroundColor if it is "default" (read nil) in IB to a color, but does not use the UIColor.green if a backgroundColor is set in IB, which is exactly what I need.
Shoutout to Eridius in the #swift-lang irc for helping me get to this answer.

Save styled element to reuse in other view controllers

I'm making an iOS app with Xcode where all my buttons should have the same style. The only difference between these buttons are their height and width. Is there a way to save the first one I styled, and then use it again in the different view controllers, without copying? I'm thinking if this is possible it'll save me a lot of time.
Applying the same style to multiple instances of UIButton:
Strictly Programmatic route:
The first two methods are what I would do. The third is only to illustrate that it is possible to write an init that copies settings from another button.
Apply preset style with a sub class:
class StyledButton : UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.blackColor()
// more styling
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Apply preset style with an extension to UIButton:
extension UIButton {
func setCustomStyle1() {
self.backgroundColor = UIColor.blackColor()
// nore styling
}
}
Copy style with a convenience init in an extension to UIButton:
extension UIButton {
convenience init(styleFromButton button: UIButton, frame: CGRect) {
self.init(frame: frame)
self.backgroundColor = button.backgroundColor
}
}
Interface Builder solution:
Create a new Swift file:
Create a sub class of UIButton in the new file:
class StyledButton : UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
style()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
style()
}
private func style() {
self.backgroundColor = UIColor.blackColor()
// more styling
}
}
Go back to the Interface Builder and select a UIButton you want to style.
Select the third panel on the right, this is the identity inspector.
Select your sub class as the class for the UIButton.
Repeat for all buttons to style.
Or style the entire thing in IB and Alt-Drag to make a copy.

Resources