Adding a ViewController into a UICollectionviewcell - swift

I would like to embed a ViewController inside a UICollectionView cell, I tried to search on the internet but I haven't found anything applicable to my case.
I've done this so far,
this is the View Controller:
class ExploreViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
}
}
This is the collectionViewCell:
class ExploreCollectionViewCell: UICollectionViewCell {
let exploreViewController = ExploreViewController()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(exploreViewController.view)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Basically I'm instantiating a ViewController inside the cell and displaying its view;
I don't think this is actually the best thing to do but honestly I don't know how to implement it in a different way.
The best thing would be to actually embed the viewController inside the cell, do you know how could I do it?

Related

how to customize a label when is not in viewdidload?

I have those variables in collectionviewcell file and I want to change label background and cornerradius but that file doesnt have a viewdidload how can I do that . Thanks for helps.
UIView subclasses do not have a viewDidLoad method, instead you use the view's initializer:
class MyCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
layoutUI()
}
private func layoutUI() {
label.layer.cornerRadius = 5
label.backgroundColor = .blue
}
}

Change IBOutlet button's type

I'm trying to achieve something I'm not sure if it's doable. I have a xib for UITableViewCell that has a UIButton in it with custom class assigned in storyboard i.e MainButtonSuperClass. In UITableViewCell.swift outlet is connected like following,
#IBOutlet weak var button: MainButtonSuperClass!
Many different controllers are configuring this TableViewCell but button's UI will be different for all those controllers as defined in subclass i.e.
final class MainButtonSubClass: MainButtonSuperClass {
override func configure(){//different style of button }
}
How can I achieve this? so far I have tried following,
let button: MainButtonSuperClass = MainButtonSubClass()
button.configure()
cell.button = button
But this doesn't pick the style
EDIT:
//tableview cell
class TableViewCell: UITableViewCell {
#IBOutlet weak var button: MainButtonSuperClass!
}
//Controller A wants default style of superclass (MainButtonSuperClass)
func configureButton(buttonCell: TableViewCell) {
buttonCell.button.configure() //works
}
//Controller B wants different style of subclass (MainButtonSubClass)
func configureButton(buttonCell: TableViewCell) {
let button: MainButtonSuperClass = MainButtonSubClass()
button.configure()
cell.button = button // doesn't work or adopts the style
}
//Custom button's classes
final class MainButtonSuperClass: UIButton {
override func configure(){//styled button }
}
final class MainButtonSubClass: MainButtonSuperClass {
override func configure(){//different style of button }
}
Ok understand, let's try this
class CustomClass: UIButton {
class Type1Class: UIButton {
// Do all the setup here
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class Type2Class: UIButton {
// Do all the setup here
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
Then you can initialize it with the following:
#IBOutlet weak var button: CustomClass.Type1Class!
Hope it helps!
I found the solution. I will not use IBOutlet but just a property of UIButton that I will change dynamically with factory method. With IBOutlet it's not possible.

How to Observer UITexFiled startEditing and EndEditing in its SubClass?

How to observer in UITexFiled sub class ,if current textField is started Ending or Ended Editing in same class .
if I'll write self.delegate = self then my ViewController UITextField method will not called .
I want to make a UITexFiled SubClass when every editing is started then I'll scale up the textFiled ,and when editing is done then UITexField will be back to normal size . but I want to handle from my subclass not to write logic every UITexFeildDelegate in all ViewController Please help me .
You can add targets for the specific events
class MyTextField: UITextField {
override init(frame: CGRect) {
super.init(frame:frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
self.addTarget(self, action: #selector(didBegin), for: .editingDidBegin)
self.addTarget(self, action: #selector(didEnd), for: .editingDidEnd)
}
#objc func didBegin() {
}
#objc func didEnd() {
}
}

IBOutlet is nil in IBDesignable class

I have a custom view class that is supposed to just contain a label. I have an extension in each target that will provide the text that should be displayed in the view, this way I don't have recreate each controller just to have a different label and background color in it.
My custom code is:
#IBDesignable
class HomeAccentView: UIView {
#IBOutlet weak var nameLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
private func setup() {
backgroundColor = UIColor.main
nameLabel.text = String.headerText
nameLabel.textColor = UIColor.white
}
}
I have my nib's file owner as HomeAccentView and the label is connected as an outlet on the storyboard.
But whenever I try to set the text of the label it's always nil. What am I missing or doing wrong?
You did not set class for view. You set only file owner, which means that you told that HomeAccessView is responsible for loading the view, but your code is not showing this. Is there any motive behind this? Otherwise, remove class from file owner and set it for view.

How to Pass extra parameters to a custom UIView class for initialization in swift

I'm trying to write a class that is of type UIView, but on initialization I want it to take an extra parameter, but I can't figure out how to get around the UIView needing its params instead. Any help is much appreciated!
class MenuBar: UIView {
let homeController: HomeController
init(controller: HomeController){
homeController = controller
super.init()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In the ViewController I'm initializing it like this:
let menuBar: MenuBar = {
let mb = MenuBar(controller: self)
return mb
}()
Try this.
class MenuBar: UIView {
let homeController: HomeController
required init(controller: HomeController){
homeController = controller
super.init(frame: CGRect.zero)
// Can't call super.init() here because it's a convenience initializer not a desginated initializer
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
From my experience this is what works best if you want to have custom initialiser for UIView:
class CustomView : UIView {
private var customProperty: CustomClass
required init(customProperty: CustomClass) {
super.init(frame: .zero)
self.customProperty = customProperty
self.setup()
}
required override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
fileprivate func setup() {
//Here all custom code for initialisation (common for all creation methods)
}
}
This approach allows you to keep common initialisation code regardless of method of creating the view (both storyboard and code)
That's about creating UIView properly.
Additionally I would recommend to avoid passing UIViewController to UIView - I think you are trying to solve some problem in a wrong way.
Much better ways to communicate between those two is to use delegate or closure - but that's a bit off-topic - maybe you can create another question about why you want to pass it like this.