custom class swift setting constraints to superview - swift

I want to create a custom UIView that I can add to any view and have it show a red error message like instagram does in the picture. I am able to do this programmatically in my view controller but want to create a modular class that I can add it into any view where I want to show an error. My question is how can I add constraints to superview in a custom class?
For example how would I do:
topAnchor.constraint(equalTo: view.topAnchor, constant: 0)
leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0)
rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0)
widthAnchor.constraint(equalTo: errorLabel.frame.size.height,0)
In a custom class so that I don't have to do it in my view controller? Can I access whatever superView's constraints so that my view is always located at the top?
class CustomUIAlertView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Can you give guidance on how to approach this? I feel like I am missing something basic.

I think the best way is to pass the superview as parameter to the init method.
Something like that:
class CustomUIAlertView : UIView {
weak var parent:UIView
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
required init(frame:CGRect, superview:UIView) {
super.init(frame: frame)
self.parent = superview
}
}

Related

Subclassed UIButton title font size changing unexpectedly

I'm using protocol delegate to set the title of a UIButton. However, somewhere along the line the font size is unexpectedly changing from 14 to 17. I've tried subclassing the button to keep the font at size 14, but clearly something is going wrong. It's been suggested that perhaps there's a conflict somewhere with the font size. However, I can't find any code that creates conflict.
Subclassed button:
import UIKit
class typeButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel?.font = UIFont(name: "Helvetica", size: 14)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Protocol extension:
extension ObservationDetailViewController: MushroomTypeDelegate {
func didSelectMushroom(name: String) {
typeButton.setTitle(name, for: .normal)
observation?.type = name
}
} // End of Extension
The button is classed via Storyboard. If I place a breakpoint on the line setting the button title typeButton.setTitle(name, for: .normal) it shows the font at size 14 . Yet, as I move past the breakpoint the font is unexpectedly changed to a larger size. I was able to use attributed text, & setAttributedTitle to fix this, but I'm curious why the font size is being changed.
Link to GitHub file
Try setting the font size in init?(coder aDecoder: NSCoder) since you classed the button from storyboard:
class TypeButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
titleLabel?.font = UIFont(name: "Helvetica", size: 14)
}
}
And make sure the font name is correct.

What to use as NSCoder to initialize a View?

Hey guys I created a new custom View Class and now I want to build a instance of it, I initialized it with the following code:
required init?(coder aCoder: NSCoder) {
super.init(coder: aCoder)
tapRecognizer = UITapGestureRecognizer(
target: self, action: #selector(handleBarTap))
addGestureRecognizer(tapRecognizer)
}
deinit {
removeGestureRecognizer(tapRecognizer)
}
And this is the instance, but what can I use as coder?
lazy var chartView = TutorialChartView(coder: )
Thanks in advance!
When you say View, do you mean UIView? The problem is that that's the wrong initializer. init(coder:) is not something you call; it's a process initiated by the storyboard when there is one of these things in the storyboard and you load that view controller.
The code UIView designated initializer is init(frame:). Implement that and call it, and you're all set.
(You may also have to provide an implementation of init(coder:) but it should just throw a fatalError, because you do not expect to be called this way.)
You should cannot use coder as initializer for creating class, use frame instead, here is your code written in frame-style initializing.
override init(frame: CGRect) {
super.init(frame: frame)
tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleBarTap))
addGestureRecognizer(tapRecognizer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Here is how you use it:
lazy var chartView = TutorialChartView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)

Setting Corner Radius in Draw for UIImageView

I am setting some properties in the draw method of my UIImageView. However, these do not seem to be taking any affect at all. I see no rounded corners and no masking taking affect. The view is below:
//
// RoundImage.swift
//
//
import UIKit
class RoundImage: UIImageView {
//------------------
//MARK: - Setup and Initialization
//------------------
override init(frame: CGRect) {
super.init(frame: frame)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initialize()
}
override func draw(_ rect: CGRect) {
super.draw(rect)
self.layer.cornerRadius = 30
self.layer.masksToBounds = true
self.clipsToBounds = true
}
//Setups content, styles, and defaults for the view
private func initialize(){
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(){
//TODO: These values cannot be changed in interface builder, but they should be able to be
}
//------------------
//MARK: - Interface Builder Methods
//------------------
//Sets the view up for interface builder with runtime styling and temp display values
override func prepareForInterfaceBuilder() {
self.runtimeStyle()
self.staticContent()
}
//------------------
//MARK: - Lifecycle Methods
//------------------
//Sets the view up with runtime styling and values
override func awakeFromNib() {
super.awakeFromNib()
self.runtimeStyle()
self.staticContent()
}
}
UIImageView when subclassed does not call the draw method at all. It is not allowed, although minimally documented. In this case, it is recommended to subclass UIView and then draw the image on the view in your draw method yourself.
For further information:
drawRect not being called in my subclass of UIImageView

UILabel subclass appearance in Storyboard

I have created a subclass of UILabel called MyUILabel. The only thing changed is the font and font-size. It appears as expected when I run the app. However, the in the Storyboard, the default UILabel is showed. Is there any way to make Storyboards show the font and font-size from my subclass?
MyUILabel:
public class MyUILabel : UILabel {
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.font = UIFont(name: Constants.DefaultFont, size: 30)
}
}
You could make it #IBDesignable, and then implement prepareForInterfaceBuilder:
#IBDesignable
public class MyUILabel: UILabel {
public override func awakeFromNib() {
super.awakeFromNib()
configureLabel()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
configureLabel()
}
func configureLabel() {
font = UIFont(name: Constants.DefaultFont, size: 40)
}
}
Note, IB didn't like it when I implemented init(coder:), so I moved it into awakeFromNib.
Also note that when you make an #IBDesignable class, Apple advises that you create a separate target (e.g. "File" - "New" - "Target..." - "Cocoa Touch Framework") for this designable class. For more information, see WWDC 2014 video What’s New in Interface Builder.

swift IBDesignable view not show in storyboard

I want to custom a 5-star UIView,also I want it to be render in storyboard. So I decide to use #IBDesignable and #IBInspectable.The following is my code.
import UIKit
#IBDesignable
class RatingView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setUpView()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpView()
}
func setUpView() {
let imageView = UIImageView(frame:CGRectMake(0, 0, 50,50))
imageView.image = UIImage(named: "star")
addSubview(imageView)
}
}
And then in my storyboard , I pull a UIView into my canvas,and set Custom class to my custom view as RatingView.The compiler starts to compile storyboard file and I just wait for the custom view to be renderd in canvas.Here is the screenshot.
The state is "up to date",but the view has not been renderd.The view is just staying white,what I want to see is the image I add to the parent view.
When I use UILabel instead of UIImageView, the label is renderd in the canvas but not the UIImageView,how can I render my lovely star image in my canvas.(Images.xcassets has star.png file)
use UILabel instead of UIImageView
func setUpView() {
let label = UILabel(frame: CGRectMake(0, 0, 50, 50))
label.text = "text"
addSubview(label)
}
result:
I was trying to do the same exact thing. You need to put the view in a framework. As #Benson Tommy said in the comments take a look at WWDC 2014 session 411.
Here is a link to the session:https://developer.apple.com/videos/wwdc/2014/#411
Here is a link to the transcript of the session: http://asciiwwdc.com/2014/sessions/411