Swift class multiple inheritance - swift

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
}
}

Related

How do I give an SKShapeNode a color?

I want to create an SKShapeNode and I want to add a stroke color to it. But when I try it does not work and I keep on receiving this error:
Consecutive declarations on a line must be separated by ';'
Here is my code:
import SpriteKit
class Lable: SKLabelNode {
override init() {
super.init()
text = String(1)
fontSize = 128
fontName = "Futura Bold"
fontColor = .white
position = CGPoint(x: -8, y: -50)
zPosition = 4
}
func updateLable(level : Int) {
text = String(level)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class LableBackground: SKNode {
let ring = SKShapeNode(circleOfRadius: 100)
ring.strokeColor = .lightGray //ERROR ON THIS LINE
ring.alpha = 0.5
ring.lineWidth = 30
ring.zPosition = 0
//let bg = SKShapeNode(circleOfRadius: 100)
//bg.fillColor =
override init(){
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
How do I fix this problem and what did I do wrong?
Note: This is not a finished program so it might contain comments/messy code.
I tried doing ring.strokeColor = .lightGray to give my SKShapeNode a stroke color and it just gives an error every time.
You should make the code like this:
import SpriteKit
class Lable: SKLabelNode {
override init() {
super.init()
text = String(1)
fontSize = 128
fontName = "Futura Bold"
fontColor = .white
position = CGPoint(x: -8, y: -50)
zPosition = 4
}
func updateLable(level : Int) {
text = String(level)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class LableBackground: SKNode {
override init(){
super.init()
let ring = SKShapeNode(circleOfRadius: 100)
ring.strokeColor = .lightGray //ERROR ON THIS LINE
ring.alpha = 0.5
ring.lineWidth = 30
ring.zPosition = 0
//let bg = SKShapeNode(circleOfRadius: 100)
//bg.fillColor =
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

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")
}
}

Custom view's IBOutlet is nil

So I have a main viewController that has a stack view to which I want to add multiple instances of custom views I have created.
So my thought process was to create a custom view that inherits from UIView. I want the view to always be 40x40 so I created a new init to take care of this? (not sure if this is correct):
class QuickAddView: UIView {
#IBOutlet weak var iconLabel: UILabel!
var task: Task = Task()
public init(task: Task) {
self.task = task
super.init(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
configureView()
}
private func configureView() {
self.layer.cornerRadius = self.frame.size.width / 2
self.backgroundColor = task.color
configureViewElements()
}
private func configureViewElements() {
configureIconLabel()
}
private func configureIconLabel() {
// CRASH: - iconLabel is nil here
self.iconLabel.text = task.icon
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I then have a QuickAddView nib that sets its custom class to QuickAddView.swift
Lastly, I create the custom views in my viewController:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
configureViewElements()
}
private func configureViewElements() {
configureQuickAddStackView()
}
private func configureQuickAddStackView() {
let quickAddView = QuickAddView(task: Task(name: "Go to the store", icon: "🍐", color: .purple))
quickAddStackView.addArrangedSubview(quickAddView)
}
The problem I'm having is that my iconLabel is nil when I try to set up my QuickAddView. I also don't know if I'm doing this process of creating a custom view correct.
Since you are connecting the IBOutlet from xibFile you have to use
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
configureView()
}
Also in your class you have to instantiate it with
if let quickAddView = Bundle.mainBundle().loadNibNamed("QuickAddView", owner: self, options: nil).first as? QuickAddView {
quickAddView.task = task
}
The problem is that you're creating a custom view in code, but using an IBOutlet for the iconLabel. An IBOutlet is for something you've built in Interface Builder, not in code. If you want to create the QuickAddView in code, you need to also create the iconLabel in code, in the QuickAddView class. You need to make these modifications:
weak var iconLabel: UILabel?
private func configureIconLabel() {
iconLabel = UILabel(frame: CGRect())
if let iconLabel = iconLabel {
iconLabel.text = task.icon
addSubview(iconLabel)
}
}
Note that I passed in a zeroed out CGRect, but you'll want to use whatever you want the UILabels origin and size to be, or use autolayout to configure where the iconLabel is displayed.

How to bring a subview to front when selected in Swift?

So I've got two views, both added to the superview programmatically:
//First added view to my superView (baseView)
let imageViewOne = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
baseView.addSubview(imageViewOne)
//Second added view to my superView (baseView)
let imageViewTwo = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
baseView.addSubview(imageViewTwo)
I want to bring one of them to the front when it is selected because when you add a new view, it overlaps the previous one. Something that works with "selected" or "touched".
Use this:
baseView.bringSubview(toFront: imageViewOne)
You can do this by UITapGestureRecognizer by setting Restoration ID from the interface builder
func tapOneAct(sender: UITapGestureRecognizer) {
if(sender.view!.restorationIdentifier == "view1")
// view1 is `Restoration ID` of imageViewOne
{
view.bringSubview(toFront: imageViewOne)
}
if(sender.view!.restorationIdentifier == "view2")
// view2 is `Restoration ID` of 2nd view
{
view.bringSubview(toFront: imageViewTwo)
}
}
If I understand correctly then you would like to check the status of selected view and bring it to the front of the view hierarchy.
In this case you have to do following things:
1) track selection state, let it will be var isSelected: Bool in code snippet
2) hold a callback for an action when view is selected (you can use for example UIButton to observe tap event)
In following code snippet you can check the selection state when the view is touched.
BaseView implements logic for checking the state of SelectionView.
import UIKit
final class SelectionView<T: UIView>: UIView {
var onTap: ((_ isSelected: Bool) -> ())?
// MARK: - Private
private let view: T
private let button = UIButton(type: .custom)
private var isSelected: Bool = false
// MARK: - Init
init(view: T) {
self.view = view
super.init(frame: .zero)
setUp()
}
// MARK: - Private
private func setUp() {
addSubview(view)
addSubview(button)
button.addTarget(self, action: #selector(onButtonTap), for: .touchUpInside)
}
#objc private func onButtonTap() {
isSelected = !isSelected
onTap?(isSelected)
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
view.frame = bounds
button.frame = bounds
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
return view.sizeThatFits(size)
}
// MARK: - Unused
override init(frame: CGRect) {
fatalError("init(frame:) has not been implemented")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class BaseView: UIView {
init() {
super.init(frame: .zero)
let views = [SelectionView(view: UIView()), SelectionView(view: UIView())]
for view in views {
view.onTap = { [weak self, weak view] isSelected in
guard let selectedView = view
else { return }
if isSelected {
self?.bringSubview(toFront: selectedView)
}
}
}
}
// MARK: - Unused
override init(frame: CGRect) {
fatalError("init(frame:) has not been implemented")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Subclassing UIView in 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