Subclassing UIView in swift - swift

When subclassing UIView, how do you access the parent classes methods and properties?... this is not working:
//
// Draw2D.swift
// Draw2D
//
import UIKit
class Draw2D: UIView {
let coloredSquare = Draw2D()
coloredSquare.backgroundColor = UIColor.blueColor()
coloredSquare.frame = CGRect(x: 0, y: 120, width: 50, height: 50)
addSubview(coloredSquare)
}
Thanks

You did not create an initialiser for the your Draw2D class. It needs this to be able to call super.init, this in turn actually creates the UIView stuff from which you are subclassing.
You also created another instance of Draw2D in your class. This is bad, if you actually do this in an initialiser (where that code belongs) it will create an infinite amount of subviews.
Recursive functions are super awesome, recursive initialiser are very bad ;)
import UIKit
class Draw2D: UIView {
// this will create an infinite amount of coloredSquare's => it is a recursive initialiser
let coloredSquare : Draw2D
override init(frame: CGRect) {
coloredSquare = Draw2D(frame: frame)
super.init(frame: frame)
self.frame = frame
coloredSquare.backgroundColor = UIColor.blueColor()
coloredSquare.frame = CGRect(x: 0, y: 120, width: 50, height: 50)
addSubview(coloredSquare)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
After calling super.init() you can call stuff from the super class. Use self for extra clarity, but this is not needed.
class Draw2DCorrected: UIView {
init() {
let rect = CGRect(x: 0, y: 120, width: 50, height: 50)
super.init(frame: rect)
self.frame = rect // inherited stuff from super class -> UIView
self.backgroundColor = UIColor.blueColor() // inherited stuff from super class -> UIView
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
var coloredSquare = Draw2DCorrected() // playground only

Related

An additional view overlay the main view

I have a main view where there are buttons and google map.
let maps = MapView(frame: view.bounds)
mapview = maps
view.addSubview(mapview!)
And by changing the state of the user, details are added to the main view in the same way.
let new = ButtonView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
ButView = new
view.addSubview(ButView!)
When adding these views, my map is overlapped by layers of additional views and I cannot do any actions. Because the extra view all overlaps, how to avoid it?
class ButtonView: UIView {
var FromButton : MainButton = MainButton()
var toButton : MainButton = MainButton()
var Send : MainButton = MainButton()
public override init(frame: CGRect) {
super.init(frame: frame)
addSubview(Send)
addSubview(FromButton)
addSubview(toButton)
addview()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Swift class multiple inheritance

I created a class like this one:
class number1: UIScrollView {
init() {
super.init(frame: CGRect(x: 9, y: 780, width: 1024, height: 267))
self.contentSize = CGSize(width: 100, height: 267)
self.backgroundColor = UIColor.clear
self.autoresizingMask = UIView.AutoresizingMask(rawValue: UIView.AutoresizingMask.RawValue(UInt8(UIView.AutoresizingMask.flexibleWidth.rawValue)))
//followed by do blablabla I dont want in my new class
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Now I want a 2nd class similar to my 1st class but without the blablabla.
class number2: number1 {
override init() {
super.init()
self.frame = CGRect(x: 400, y: 10, width: 196, height: 500)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I am doing it this way but dont know how to remove the "blablabla". The easiest would be to inherit the init from UIScrollView instead of class number1. How to do that?
Just the bare bones here but should be enough:
class number1: UIScrollView {
init() {
super.init()
// Do stuff common to all classes
setup()
}
func setup() {
// Do stuff for this class
}
}
class number2: number1 {
override func setup() {
// Do stuff for this class only
}
}

NSScrollView subclass doesn't scroll

I'm making a macOS app and i have created a simple NSScrollView subclass. However, the scrollview doesn't scroll.
When i set the property NSScrollView.hasHorizontalScroller or the property NSScrollView.hasVerticalScroller to true,
then the scrolling works. But i want the scrollbars to be hidden, so these properties will be set to false.
This is my swift (playground) code:
import Cocoa
import PlaygroundSupport
class MyScrollView: NSScrollView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
// fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
}
let scrollView = MyScrollView(frame: NSRect(x: 0, y: 0, width: 480, height: 240))
// scrollView.hasHorizontalScroller = true
// Image of 1280 x 854.
let img = NSImage(byReferencing: URL(fileURLWithPath: "/users/username/Pictures/some-image.jpg"))
let imgView = NSImageView(frame: NSRect(x: 0, y: 0, width: img.size.width, height: img.size.height))
imgView.image = img
scrollView.documentView = imgView
PlaygroundPage.current.liveView = scrollView
I have compared many properties with a normal NSScrollView, but i can't figure it out.
What am i doing wrong?
Thanks in advance.

Swift - UIView when done updating its frame?

I have a UITableViewCell in which I add my custom view, say
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience required init(size: CGFloat) {
self.init(frame: CGRect.zero)
height = size
// init my other sub contents [1]
}
}
From my UITableViewCell:
let myView = MyView(size: 35)
contentView.addSubView(myView)
My problem: my other UI components in MyView depend on the width and height of MyView and it's too early to set their position in [1] because MyView's frame is now (x: 0, y: 0, width: 0, height: height)
Where should I put my other UI components in MyView? Is there a delegate in UIView that tells me: "Hey, the frame of the view is updated with its actual size."? (like viewDidAppear in a UIViewController)
Regards,
You can do
override var frame: NSRect {
didSet {
//update your subviews
}
}
In your MyView class. But really, you should just look into setting up proper constraints:
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/

How do you subclass UIView and add another UIView inside of it with the same frame

Hi I am trying to create a custom loading bar view by subclassing UIView. I want to create one UIView with a fixed frame, and another UIView that is inside of it. When I initialize the inner UIView, with the frame passed in by this method override init(frame: CGRect), the two views have different origins. I want the two views to be directly on top of each other to start out. I also want to be able to update the innerBar by calling this uploadBar.setLoadingPercentage(percent: 53.5)
Here is the code:
Creating the UploadBar
let uploadBar = UploadBar(frame: CGRect(x: 40, y: 40, width: 400, height: 40))
view.addSubview(uploadBar)
Subclassing UploadBar
import UIKit
class UploadBar: UIView {
var innerBar: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
innerBar = UIView(frame: frame)
innerBar.backgroundColor = UI.customBlue()
addSubview(innerBar)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setLoadingPercentage(percent: Double) {
// change innerBar's frame and redraw
}
}
For your inner view, you only require the width and height from the parent rect. The x and y should be zero relative to the parent view:
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
let innerRect = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
innerBar = UIView(frame: innerRect)
innerBar.backgroundColor = UI.customBlue()
addSubview(innerBar)
}