How to navigate another view controller when clicking on item inside cell of collectionView Using Swift 3 - ios

We want to show another controller by replacing main controller when clicking on item (i.e ImageView) inside a cell collection. But we are not able to get main collection view and can't able to navigate targeted controller. We are using following approach -
HomeViewComtroller.swift
import LBTAComponents
class HomeViewController: DatasourceController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Home"
collectionView?.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.backgroundColor = UIColor(r: 232, g: 236, b: 241, a: 1)
let homeViewDatasource = HomeViewDatasource()
self.datasource = homeViewDatasource
}
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.section == 0 {
return CGSize(width: view.frame.width, height: 120)
} else if indexPath.section == 6 {
return CGSize(width: view.frame.width, height: 120)
} else {
return CGSize(width: view.frame.width, height: 200)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 33)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 10)
}
// lazy var homeMainCatgCell: HomeMainCatgCell = {
// let homemain = HomeMainCatgCell ()
// homemain.homeViewcontroller = self
// return homemain
// }()
func handleCtgClick (ctgname: String ,ctgId: String) {
let dummySettingViewController = UIViewController()
dummySettingViewController.view.backgroundColor = UIColor.white
dummySettingViewController.navigationItem.title = ctgname
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingViewController, animated: true)
}
}
HomeViewDatasource
import LBTAComponents
class HomeViewDatasource: Datasource {
override func headerClasses() -> [DatasourceCell.Type]? {
return [HomeMainCatgCellHeader.self,HomeSaleCatgCellHeader.self,HomeNewArrivalCellHeader.self,HomeBestSallingCellHeader.self,HomeBigDiscountCellHeader.self,HomeSpecialOfferCellHeader.self,HomeBrandCellHeader.self]
}
override func footerClasses() -> [DatasourceCell.Type]? {
return[HomeCellsFooter.self]
}
override func cellClasses() -> [DatasourceCell.Type] {
return [HomeMainCatgCell.self,HomeSaleCtagCell.self,HomeNewArrivalsCell.self,HomeBestSallingCatgCell.self,HomeBigDiscountCatgCell.self,HomeSpecialOfferCatgCell.self,HomeBrandVIewCell.self]
}
override func numberOfItems(_ section: Int) -> Int {
return 1
}
override func numberOfSections() -> Int {
return 7
}
}
HomeMainCatgCell.swift
import LBTAComponents
class HomeMainCatgCell: DatasourceCell {
var homeViewcontroller: HomeViewController?
let personalcareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "personalcareimage")
iv.tag = 0
iv.contentMode = .scaleToFill
return iv
}()
let healthcareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "healthcareimage")
iv.contentMode = .scaleToFill
iv.tag = 1
return iv
}()
let homecareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "homecareimage")
iv.contentMode = .scaleToFill
iv.tag = 2
return iv
}()
let kitchencareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "kitchencareiamge")
iv.contentMode = .scaleToFill
iv.tag = 3
return iv
}()
override func setupViews() {
super.setupViews()
let personalcareCatgImageContainerView = UIView()
personalcareCatgImageContainerView.backgroundColor = .white
let homecareCatgImageContainerView = UIView()
homecareCatgImageContainerView.backgroundColor = .white
let healthcareCatgImageContainerView = UIView()
healthcareCatgImageContainerView.backgroundColor = .white
let kitchencareCatgImageContainerView = UIView()
kitchencareCatgImageContainerView.backgroundColor = .white
let imageStackView = UIStackView(arrangedSubviews: [personalcareCatgImageContainerView,homecareCatgImageContainerView,healthcareCatgImageContainerView,kitchencareCatgImageContainerView])
imageStackView.axis = .horizontal
imageStackView.distribution = .fillEqually
addSubview(imageStackView)
imageStackView.anchor(topAnchor, left: leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: frame.width, heightConstant: frame.height)
imageStackView.addSubview(personalcareCatgImageView)
imageStackView.addSubview(healthcareCatgImageView)
imageStackView.addSubview(homecareCatgImageView)
imageStackView.addSubview(kitchencareCatgImageView)
personalcareCatgImageView.anchor(personalcareCatgImageContainerView.topAnchor, left: personalcareCatgImageContainerView.leftAnchor, bottom: personalcareCatgImageContainerView.bottomAnchor, right: personalcareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: personalcareCatgImageContainerView.frame.width , heightConstant: personalcareCatgImageContainerView.frame.width)
healthcareCatgImageView.anchor(healthcareCatgImageContainerView.topAnchor, left: healthcareCatgImageContainerView.leftAnchor, bottom: healthcareCatgImageContainerView.bottomAnchor, right: healthcareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: healthcareCatgImageContainerView.frame.width , heightConstant: healthcareCatgImageContainerView.frame.width)
homecareCatgImageView.anchor(homecareCatgImageContainerView.topAnchor, left: homecareCatgImageContainerView.leftAnchor, bottom: homecareCatgImageContainerView.bottomAnchor, right: homecareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: homecareCatgImageContainerView.frame.width , heightConstant: homecareCatgImageContainerView.frame.width)
kitchencareCatgImageView.anchor(kitchencareCatgImageContainerView.topAnchor, left: kitchencareCatgImageContainerView.leftAnchor, bottom: kitchencareCatgImageContainerView.bottomAnchor, right: kitchencareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: kitchencareCatgImageContainerView.frame.width , heightConstant: kitchencareCatgImageContainerView.frame.width)
personalcareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
personalcareCatgImageView.isUserInteractionEnabled = true
healthcareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
healthcareCatgImageView.isUserInteractionEnabled = true
homecareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
homecareCatgImageView.isUserInteractionEnabled = true
kitchencareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
kitchencareCatgImageView.isUserInteractionEnabled = true
}
func handleClickCtg(gestureRecognizer: UITapGestureRecognizer) {
var CtgName: String? = nil
var CtgId: String? = nil
guard let tag = gestureRecognizer.view?.tag else {return}
print(tag)
switch tag {
case 0:
CtgName = "Personal Care"
CtgId = "121"
case 1:
CtgName = "Health Care"
CtgId = "122"
case 2:
CtgName = "Home Care"
CtgId = "123"
case 3:
CtgName = "Kitchen Care"
CtgId = "124"
default:
return
}
self.homeViewController?.handleCtgClick(ctgname: CtgName! ,ctgId: CtgId!)
}
}
Main Problem
first of all i am not binding the click of entire cell, I only want to bing click on ImageView inside cell. So for that i bind GestureRecognizer on image view like -
kitchencareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
Click event works fine in terms of it's print the tag (added on image view) via print(tag) inside click function. But when call function self.homeViewcontroller.handleCtgClick(ctgname: CtgName! ,ctgId: CtgId!) (function exist in HomeViewcontroller class). it's not changing the view controller.
I also debug handleCtgClick function and i found i am getting the object of HomeViewcontroller is nil.
thanks in Advance

If you declare a global instance of your controller in your cell class this will create a Reference cycle and create a leak in your app. Your cell will have a strong reference to your controller and your controller will have a strong reference to your tableview which in turn keeps a strong reference to the cell, and second you might not be able to tell the index path of the clicked cell if you allow editing. You can try the following method to overcome both problems.
First of all create an enum in your cell class with cases as named according to your image views so your controller knows which image view is clicked and you can link your tags to it too. Something like:
enum CategoryViews:Int{
case personal = 0,healthcare = 1,homecare = 2,kitchencare = 3
}
Then create a protocol in your cell class like:
protocol HomeMainCatgCellDelegate:class{
func clicked(view:CategoryViews,forCell cell:HomeMainCatgCell)
}
Then create a weak variable in your cell class and call the protocol method in your action handler method
class HomeMainCatgCell: DatasourceCell {
weak var delegate:HomeMainCatgCellDelegate?
//Remove the variable var homeViewcontroller: HomeViewController? to avoid reference cycle and we don't need it anyway.
...
func handleClickCtg(gestureRecognizer: UITapGestureRecognizer) {
guard let tag = gestureRecognizer.view?.tag else {return}
print(tag)
if let clickedImageView = CategoryViews(rawValue:tag){
self.delegate?.clicked(view:clickedImageView,forCell:self)
}
}
}
Then in your view controller class you can you have to confirm to the HomeMainCatgCellDelegate protocol and set the cell's delegate to self.
class HomeViewController: DatasourceController, HomeMainCatgCellDelegate{
...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//Dequeue your cell here
cell.delegate = self
...
return self
}
func clicked(view:CategoryViews,forCell cell:HomeMainCatgCell){
//And you can handle your events accordingly here
if let indexpath = self.collectionView.indexPath(for: cell){
//Here you will get the indexpath of clicked cell and then you can put a switch condition to check which imageview is clicked
switch view{
case .personal:break
case .healthcare:break
case .homecare:break
case .kitchencare:break
}
}
}
}
Hope this helps.

The problem is that your "homeViewcontroller" variable is not set up correctly.
This code:
var homeViewcontroller = HomeViewController()
Creates an instance of a HomeViewController class. But this instance is in no way related to the screen you think it is. The screen that presented your current view is a completely different instance.
To be honest the way you are chaining everything is pretty weird and its not very intuitive. But if you want to fix your problem without altering your code too much you have to pass the REAL HomeViewController downwards.
So on the HomeViewController.swift you have this code:
let homeViewDatasource = HomeViewDatasource()
self.datasource = homeViewDatasource
Pass the "handleCtgClick" as a closure to it.
Something like
homeViewDataSource.presenterClosure = {(ctgname: String ,ctgId: String) in
let dummySettingViewController = UIViewController()
dummySettingViewController.view.backgroundColor = UIColor.white
dummySettingViewController.navigationItem.title = ctgname
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingViewController, animated: true)
}
(Note that you have to create this closure variable declaration within your HomeViewDatasource.swift so that you can assign it from the HomeViewController.swift)
Then repeat this step again to pass it to the HomeMainCatgCell.swift
Then you will be able to call this function referencing the local closure variable you created.
ALTERNATIVELY:
You can just pass the reference to the HomeViewController itself. But if you decide to do this make sure you keep passing it as an "optional" variable with a "weak" property or you will create a retain loop.

Related

Perform Segue is not working when i am using programmatic UI

I am creating an app for my personal project using programmaticUI and storyboard for the UI part, but i found an issue when i tried to performSegue from my "SecondViewController" to my "ThirdViewController" , i added the "identifier" in my segue like usual:
And then i called the "performSegue" from my SecondViewController:
import UIKit
class SecondViewController: UIViewController {
private var myItem = [SecondItem]()
lazy var myTableView : UITableView = {
let myTable = UITableView()
myTable.translatesAutoresizingMaskIntoConstraints = false
return myTable
}()
private let myContentView : UIView = {
let view = UIView()
view.backgroundColor = .gray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var label : UILabel = {
let myLabel = UILabel()
myLabel.text = "Hello"
return myLabel
}()
private let unameTextField : UITextField = {
let txtField = UITextField()
txtField.backgroundColor = .white
txtField.placeholder = "Username"
txtField.borderStyle = .roundedRect
txtField.translatesAutoresizingMaskIntoConstraints = false
return txtField
}()
private let pwordTxtField : UITextField = {
let txtField = UITextField()
txtField.placeholder = "Password"
txtField.borderStyle = .roundedRect
txtField.translatesAutoresizingMaskIntoConstraints = false
return txtField
}()
private let loginBtn : UIButton = {
let btn = UIButton(type: .system)
btn.backgroundColor = .blue
btn.setTitle("Login", for: .normal)
btn.tintColor = .white
btn.layer.cornerRadius = 5
btn.clipsToBounds = true
btn.translatesAutoresizingMaskIntoConstraints = false
btn.addTarget(self, action: #selector(btnPressed), for: .touchUpInside)
return btn
}()
//I called the "performSegue" here
#objc func btnPressed() {
performSegue(withIdentifier: "gotoBla", sender: self)
print("button pressed")
}
lazy var imageView : UIImageView = {
let image = UIImage(named: "image_4")
let imageView = UIImageView(image: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
func setAutoLayout(){
let guide = view.safeAreaLayoutGuide
myContentView.anchor(top: guide.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: view.frame.height / 3, enableInsets: true)
imageView.anchor(top: myContentView.topAnchor, left: nil , bottom: nil , right: nil , paddingTop: 10, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 80, height: 80, enableInsets: true)
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
unameTextField.anchor(top: imageView.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor, paddingTop: 10, paddingLeft: 20, paddingBottom: 5, paddingRight: 20, width: 0, height: 40, enableInsets: true)
pwordTxtField.anchor(top: unameTextField.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40, enableInsets: true)
loginBtn.anchor(top: pwordTxtField.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor , paddingTop: 20, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40, enableInsets: true)
//TableView
myTableView.topAnchor.constraint(equalTo: myContentView.bottomAnchor).isActive = true
myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
myItem.append(SecondItem(text: "first"))
myItem.append(SecondItem(text: "Second"))
myItem.append(SecondItem(text: "Third"))
view.backgroundColor = .white
view.addSubview(myContentView)
myContentView.addSubview(unameTextField)
myContentView.addSubview(pwordTxtField)
myContentView.addSubview(loginBtn)
myContentView.addSubview(imageView)
myTableView.register(SecondTableViewCell.self, forCellReuseIdentifier: K.SecondTableViewCell.identifier)
myTableView.delegate = self
myTableView.dataSource = self
view.addSubview(myTableView)
setAutoLayout()
}
}
extension SecondViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
}
}
extension SecondViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
myItem.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.SecondTableViewCell.identifier, for: indexPath) as! SecondTableViewCell
cell.second = myItem[indexPath.row]
cell.selectionStyle = .none
return cell
}
}
And for the Third View Controller, i am not yet adding some code in there
import UIKit
class ThirdViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
But everytime i run the app and click the login button,it always gave me this error:
This is what my app looks like:
Do i miss something here? I am a beginner by the way, i hope you guys can help me. Thank you
When posting questions here, it would be good for you to take a few minutes to review How to Ask
However, based on the little bit of info you've provided...
Almost certainly the problem is that you are adding View Controllers in Storyboard and then improperly trying to use them via code.
For example, I'm guessing that you have code in your "first" view controller to load and display SecondViewController like this:
#objc func showSecondTapped(_ sender: Any) {
let vc = SecondViewController()
navigationController?.pushViewController(vc, animated: true)
}
and then in SecondViewController you're trying to use the Storyboard associated segue with this:
#objc func btnPressed(_ sender: Any) {
performSegue(withIdentifier: "gotoBla", sender: self)
print("button pressed")
}
However, that segue doesn't exist as part of SecondViewController code ... it is part of the Storyboard object.
Back in your first view controller, if you load and push to SecondViewController like this:
#objc func showSecondTapped(_ sender: Any) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "secondVC") as? SecondViewController {
navigationController?.pushViewController(vc, animated: true)
}
}
you will then be able to call performSegue because you loaded it from the Storyboard.
if let vc = storyboard?.instantiateViewController(withIdentifier: "secondVC") as? SecondViewController {
navigationController?.pushViewController(vc, animated: true)
// if navigationController?.pushViewController doesn't work you can try this
present(vc, animated: true) {
// anything you want to perform after presenting new screen
}
// and try this to show in full screen with different transition effect
vc.modalTransitionStyle = .crossDissolve
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true) {
// anything you want to perform after presenting new screen
}
}

Swift reload collection view with button click not works

I am new to swift. I used LTBA components to build swift app. I follow some tutorial to develop social application like twitter. I start implement to follow button functions. its call the the another API call but same response come with minor modification(e.g - number of follower property increase by one). call also perfectly working. but collection view did not reload.my code is.
ViewConroller
import LBTAComponents
import TRON
import SwiftyJSON
class HomeDatasourceController: DatasourceController {
let errorMessageLabel: UILabel = {
let label = UILabel()
label.text = "Apologies something went wrong. Please try again later..."
label.textAlignment = .center
label.numberOfLines = 0
label.isHidden = true
return label
}()
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
collectionViewLayout.invalidateLayout()
}
func follow(){
print("inside controller")
Service.sharedInstance.fetchfollowHomeFeed { (homeDatasource, err) in
if let err = err {
self.errorMessageLabel.isHidden = false
if let apiError = err as? APIError<Service.JSONError> {
if apiError.response?.statusCode != 200 {
self.errorMessageLabel.text = "Status code was not 200"
}
}
return
}
self.datasource = homeDatasource
self.collectionView?.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(errorMessageLabel)
errorMessageLabel.fillSuperview() //LBTA method call
collectionView?.backgroundColor = UIColor(r: 232, g: 236, b: 241)
setupNavigationBarItems()
Service.sharedInstance.fetchHomeFeed { (homeDatasource, err) in
if let err = err {
self.errorMessageLabel.isHidden = false
if let apiError = err as? APIError<Service.JSONError> {
if apiError.response?.statusCode != 200 {
self.errorMessageLabel.text = "Status code was not 200"
}
}
return
}
self.datasource = homeDatasource
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//first section of users
if indexPath.section == 0 {
guard let user = self.datasource?.item(indexPath) as? User else { return .zero }
let estimatedHeight = estimatedHeightForText(user.bioText)
return CGSize(width: view.frame.width, height: estimatedHeight + 66)
} else if indexPath.section == 1 {
//our tweets size estimation
guard let tweet = datasource?.item(indexPath) as? Tweet else { return .zero }
let estimatedHeight = estimatedHeightForText(tweet.message)
return CGSize(width: view.frame.width, height: estimatedHeight + 74)
}
return CGSize(width: view.frame.width, height: 200)
}
private func estimatedHeightForText(_ text: String) -> CGFloat {
let approximateWidthOfBioTextView = view.frame.width - 12 - 50 - 12 - 2
let size = CGSize(width: approximateWidthOfBioTextView, height: 1000)
let attributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let estimatedFrame = NSString(string: text).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
return estimatedFrame.height
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 1 {
return .zero
}
return CGSize(width: view.frame.width, height: 50)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
if section == 1 {
return .zero
}
return CGSize(width: view.frame.width, height: 64)
}
}
DataCell
import LBTAComponents
class UserCell: DatasourceCell {
override var datasourceItem: Any? {
didSet {
guard let user = datasourceItem as? User else { return }
followButton.addTarget(self, action: #selector(follow), for: .touchUpInside)
nameLabel.text = user.name
usernameLabel.text = user.username
bioTextView.text = user.bioText
profileImageView.loadImage(urlString: user.profileImageUrl)
}
}
let profileImageView: CachedImageView = {
let imageView = CachedImageView()
imageView.image = #imageLiteral(resourceName: "profile_image")
imageView.layer.cornerRadius = 5
imageView.clipsToBounds = true
return imageView
}()
let nameLabel: UILabel = {
let label = UILabel()
label.text = "Brian Voong"
label.font = UIFont.boldSystemFont(ofSize: 16)
return label
}()
let usernameLabel: UILabel = {
let label = UILabel()
label.text = "#buildthatapp"
label.font = UIFont.systemFont(ofSize: 14)
label.textColor = UIColor(r: 130, g: 130, b: 130)
return label
}()
let bioTextView: UITextView = {
let textView = UITextView()
textView.text = "iPhone, iPad, iOS Programming Community. Join us to learn Swift, Objective-C and build iOS apps!"
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .clear
return textView
}()
let followButton: UIButton = {
let button = UIButton()
button.layer.cornerRadius = 5
button.layer.borderColor = twitterBlue.cgColor
button.layer.borderWidth = 1
button.setTitle("Follow", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.setTitleColor(twitterBlue, for: .normal)
button.setImage(#imageLiteral(resourceName: "follow"), for: .normal)
button.imageView?.contentMode = .scaleAspectFit
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -8, bottom: 0, right: 0)
// button.titleEdgeInsets = UIEdgeInsets
return button
}()
func follow(){
print("inside source")
var link = HomeDatasourceController()
link.follow()
}
override func setupViews() {
super.setupViews()
backgroundColor = .white
separatorLineView.isHidden = false
separatorLineView.backgroundColor = UIColor(r: 230, g: 230, b: 230)
addSubview(profileImageView)
addSubview(nameLabel)
addSubview(usernameLabel)
addSubview(bioTextView)
addSubview(followButton)
profileImageView.anchor(self.topAnchor, left: self.leftAnchor, bottom: nil, right: nil, topConstant: 12, leftConstant: 12, bottomConstant: 0, rightConstant: 0, widthConstant: 50, heightConstant: 50)
nameLabel.anchor(profileImageView.topAnchor, left: profileImageView.rightAnchor, bottom: nil, right: followButton.leftAnchor, topConstant: 0, leftConstant: 8, bottomConstant: 0, rightConstant: 12, widthConstant: 0, heightConstant: 20)
usernameLabel.anchor(nameLabel.bottomAnchor, left: nameLabel.leftAnchor, bottom: nil, right: nameLabel.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 20)
bioTextView.anchor(usernameLabel.bottomAnchor, left: usernameLabel.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: -4, leftConstant: -4, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
followButton.anchor(topAnchor, left: nil, bottom: nil, right: self.rightAnchor, topConstant: 12, leftConstant: 0, bottomConstant: 0, rightConstant: 12, widthConstant: 120, heightConstant: 34)
}
}
It using LBTA components.i tried self.collectionView?.reloadData() but its not reloaded. Please help me to fix this problem.Please help me to figure out this problem
Note that you are using a closure in the follow() method so you need to write the code for reloading, in the main queue.
write your reload code in follow like this
DispatchQueue.main.async{
self.collectionView.reloadData()
}
Try to add a completion handler for the follow method:
func follow(completionHandler: #escaping (Any, NSError?) -> ()){
Service.sharedInstance.fetchfollowHomeFeed { (homeDatasource, err) in
do {
// handle the response from the api call
completionHandler(homeDatasource, nil)
} catch let err{
self.errorMessageLabel.isHidden = false
if let apiError = err as? APIError<Service.JSONError> {
if apiError.response?.statusCode != 200 {
self.errorMessageLabel.text = "Status code was not 200"
}
}
}
}
}
And call your method like:
self.follow() {homeDatasource,error in
self.collectionView.reloadData()
}

Inaccuracy addSubview in UICollectionViewCell

There was a big problem that I can not solve for a couple of days.
I have a UIViewController with UICollectionView in which there will be 3 cells with different content. Here is my class:
class PostView: AppViewAddMenu, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var homeController: FeedController?
var contentArray = [PostContentModel]()
var postInfo: PostModel?
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 3
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.delegate = self
cv.dataSource = self
cv.backgroundColor = .white
return cv
}()
override func setupViewController() {
collectionView.register(PostViewCell.self, forCellWithReuseIdentifier: "cellId")
view.addSubview(collectionView)
view.addConstraintsWithFormat("H:|[v0]|", views: collectionView)
view.addConstraintsWithFormat("V:|-60-[v0]|", views: collectionView)
fetchPost(id: postInfo?.id)
}
func fetchPost(id: Int?){
guard let ID = id else {
print("ID faild")
return
}
let url: String = "https://FTP.ru/wp-json/mobileApi/v1/post/\(ID)"
ApiService.sharedInstance.fetchContent(url: url, completion: { (Posts: [PostContentModel]) in
self.contentArray = Posts
self.collectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! PostViewCell
cell.contentArray = contentArray
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 1000)
}
}
The idea of the first cell is to take json from a site that looks like this: [switch, content]. From the switch value in UICollectionViewCell, different functions are called, which add an element in UICollectionViewCell via addSubview (). Here's the code:
class PostViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
anchor = self.topAnchor
}
var anchor: NSLayoutYAxisAnchor?
var contentArray: [PostContentModel]?{
didSet{
for number in contentArray! {
if(number.switcher == 1) {
anchor = addTextContent(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 2){
anchor = addImageContent(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 3){
anchor = addCaptionFirst(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 4){
anchor = addButtonLink(content: number.content!, link: number.link!, bottomAnchor: anchor!)
}
}
}
}
func addTextContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor{
let shortContentPost: UILabel = {
let label = UILabel()
label.text = content
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular)
return label
}()
addSubview(shortContentPost)
shortContentPost.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return shortContentPost.bottomAnchor
}
func addImageContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let image: CustomImageView = {
let image = CustomImageView()
image.image = UIImage(named: content)
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
return image
}()
let imageURL = "https://brodude.ru/wp-content/uploads/" + content.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
image.loadImageUsingUrlString(urlString: imageURL)
addSubview(image)
image.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 250)
return image.bottomAnchor
}
func addCaptionFirst(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let Caption: UILabel = {
let lb = UILabel()
lb.text = content
lb.numberOfLines = 0
lb.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.semibold)
return lb
}()
addSubview(Caption)
Caption.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 30, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return Caption.bottomAnchor
}
func addButtonLink(content: String, link: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let button: LinkButton = {
let bt = LinkButton()
bt.LinkString = link
bt.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.semibold)
bt.setTitle(content, for: UIControlState.normal)
bt.sizeToFit()
bt.titleLabel?.numberOfLines = 0
bt.contentHorizontalAlignment = .left
bt.setTitleColor(UIColor(red: 0.07, green: 0.32, blue: 0.89, alpha: 1.0), for: UIControlState.normal)
bt.addTarget(self, action: #selector(linkOut), for: .touchUpInside)
return bt
}()
addSubview(button)
button.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 20, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return button.bottomAnchor
}
The algorithm works satisfactorily, but the problem begins when the cell is updated. When scrolling, with collectionView.reloadData (). New subview layered on the past, the text becomes fatter and clogged device memory. The process continues indefinitely until it gives an error.
Example of a problem:, ,
Sorry for my English.
First of all, instead of:
addSubview(shortContentPost)
use:
contentView.addSubview(shortContentPost)
Do this for all the subviews that you add. contentView is supposed to hold your content.
Implement this prepareForReuse in your cell:
override func prepareForReuse() {
super.prepareForReuse()
let subviews = contentView.subviews
for subview in subviews {
subview.removeFromSuperview()
}
}
This will clean your cell's content before reusing the cell.
Although I would STRONGLY recommend NOT to add/remove those subviews dynamically, because then you lose much of the reuse mechanism. I would add all the views (labels/imageViews) to the cell by default, and then use their isHidden property to hide/unhide them based on the content (e.g., if an image should be show, set the isHidden to true on all the others). This would be performance-wise better for reusing, because then the UI objects will not have to be recreated everytime a cell is reused, you would just reconfigure the content of the labels/imageViews.

Why a navigation bar button item doesn't work when the textview has been resignedFirstResponder()?

Here is an odd one. I have two bar button items, one is cancel and one is done. The done button saves the text in the textview in the coreData and then pops the current view from the navigationController and goes to previous viewcontroller. The cancel button just goes to the previous controller. The whole thing works when the textview is the firstResponder() or the keyboard is up. When the keyboard resigns as the firstResponder, both buttons don't work. As in the just don't do anything. Done button doesn't save the text nor it takes me to previous viewcontroller.
Here is the code for both the buttons:
Done button:
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
Cancel button:
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
Again, the code in both these functions work when the buttons are tapped only when the textview is the first responder otherwise they don't.
ViewController code:
import UIKit
import CoreData
class editViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout,
UITextViewDelegate, UIGestureRecognizerDelegate{
var editnotes: addednotes?
var prioritynumber: Int = 1
let moContext = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
var colorArray = [prioritylevels]()
lazy var edittaskview: UITextView = {
let textview = UITextView()
textview.isScrollEnabled = false
textview.font = UIFont.systemFont(ofSize: 16)
textview.backgroundColor = .white
textview.delegate = self
return textview
}()
var clearview: UIView = {
let view = UIView()
view.backgroundColor = .clear
//view.isUserInteractionEnabled = false
return view
}()
let rightBarButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(handleDoneButton))
let leftBarButton = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
lazy var priorityCV: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.delegate = self
cv.dataSource = self
return cv
}()
let line: UIView = {
let line = UIView()
return line
}()
let reminderView: UIView = {
let reminder = UIView()
reminder.backgroundColor = .white
return reminder
}()
let reminderTitle: UILabel = {
let title = UILabel()
title.text = "Due Date"
title.textColor = .black
title.font = UIFont(name: "Avenir Next", size: 16)
title.font = UIFont.boldSystemFont(ofSize: 16)
return title
}()
let reminderMsg: UILabel = {
let title = UILabel()
title.text = "No Due Date Set"
title.textColor = .black
// title.font = UIFont(name: "Avenir Next", size: 12)
title.font = UIFont.systemFont(ofSize: 12)
return title
}()
let reminderAddBtn: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Set", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
btn.addTarget(self, action: #selector(handleSetReminderBtn), for: .touchUpInside)
return btn
}()
var textHeightConstraint: NSLayoutConstraint?
override func viewWillAppear(_ animated: Bool) {
adjustTextViewHeight()
}
let datePicker: UIDatePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red:0.97, green:0.97, blue:0.97, alpha:1.0)
datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged)
//ColorArray for PriorityCV
colorArray = [prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.73, alpha:1.0), name: " Low", prioritynumber: 1), prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.35, alpha:1.0), name: "Medium", prioritynumber: 2),prioritylevels(color: UIColor(red:0.88, green:0.63, blue:0.00, alpha:1.0), name: " High", prioritynumber: 3), prioritylevels(color: UIColor(red:0.96, green:0.28, blue:0.70, alpha:1.0), name: "Urgent", prioritynumber: 4)]
priorityCV.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cvid")
navigationItem.title = "Edit Task"
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationController?.navigationBar.tintColor = UIColor.white
navigationItem.rightBarButtonItem = rightBarButton
navigationItem.leftBarButtonItem = leftBarButton
view.addSubview(clearview)
clearview.addSubview(line)
clearview.addSubview(edittaskview)
clearview.addSubview(priorityCV)
clearview.addSubview(reminderView)
reminderView.addSubview(reminderTitle)
reminderView.addSubview(reminderMsg)
reminderView.addSubview(reminderAddBtn)
edittaskview.text = editnotes?.sNote
edittaskview.becomeFirstResponder() //taskview becomes first responder here when the view is loaded.
// view.addSubview(datePicker)
setupViews()
line.backgroundColor = editnotes?.sPriorityColor
let dismissbytap = UITapGestureRecognizer()
dismissbytap.addTarget(self, action: #selector(handleDismissByTap))
dismissbytap.delegate = self
clearview.addGestureRecognizer(dismissbytap) //a clear uiview is added behind all the subviews. this uiview is used to dismiss keyboard when tapped on it.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colorArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cvid", for: indexPath)
cell.backgroundColor = colorArray[indexPath.row].color
let prioritylabel = UILabel(frame: CGRect(x: view.frame.width / 20, y: 0, width: view.frame.width / 4, height: 30))
cell.addSubview(prioritylabel)
prioritylabel.text = colorArray[indexPath.row].name
prioritylabel.textColor = .white
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width / 4, height: 30)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
prioritynumber = colorArray[indexPath.row].prioritynumber
line.backgroundColor = colorArray[indexPath.row].color
editnotes?.sPriorityColor = colorArray[indexPath.row].color
editnotes?.sPriorityNumber = prioritynumber
print(prioritynumber)
}
func setupViews()
{
_ = edittaskview.anchor(line.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 2, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
self.edittaskview.contentInset = UIEdgeInsetsMake(2, 8, 4, 8)
self.textHeightConstraint = edittaskview.heightAnchor.constraint(equalToConstant: 80)
self.textHeightConstraint?.isActive = true
self.adjustTextViewHeight()
_ = clearview.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
_ = priorityCV.anchor(edittaskview.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 30)
_ = line.anchor(clearview.topAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 4)
_ = reminderView.anchor(priorityCV.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 30, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 60)
_ = reminderTitle.anchor(reminderView.topAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 8, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 20)
_ = reminderMsg.anchor(reminderTitle.bottomAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 4, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 24)
_ = reminderAddBtn.anchor(reminderView.topAnchor, left: nil, bottom: nil, right: reminderView.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 20, rightConstant: 32, widthConstant: 30, heightConstant: 20)
}
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
func textViewDidChange(_ textView: UITextView) {
self.adjustTextViewHeight()
}
func adjustTextViewHeight() {
let fixedWidth = edittaskview.frame.size.width
let newSize = edittaskview.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
self.textHeightConstraint?.constant = newSize.height + 15
self.view.layoutIfNeeded()
}
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
#objc func datePickerValueChanged(_ sender: UIDatePicker) {
let componenets = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: sender.date)
if let day = componenets.day, let month = componenets.month, let year = componenets.year, let hour = componenets.hour, let minute = componenets.minute {
print("\(day) \(month) \(year) \(hour) \(minute)")
}
}
#objc func handleDismissByTap() {
edittaskview.resignFirstResponder() // Resigning textview as first responder
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
This does seem odd - and I don't know why the navigation bar buttons are only calling the functions when your text view is active, but...
One way around it is to move your right and left UIBarButtonItem declarations into viewDidLoad() instead of at the class level.
As an aside, you'll get a better animation and keyboard appearance if you move edittaskview.becomeFirstResponder() from viewDidLoad() to viewDidAppear().
I don't know how but instead of creating bar buttons seperately and then assigning them like so self.navigationBarItem.leftbarbutton = leftBarbutton
I decided to construct them using UIBarButtonItem constructor.
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
It worked!
Pretty odd to be honest.
Something you could do as well is making the declaration of your UIBarButtonItem a lazy var.
It's getting instantiated with the class. If you make it a lazy var it will get created when you need to use it. If you want to keep it a let and at class level, just do:
override func viewDidLoad() {
super.viewDidLoad()
yourBarButtonItem.target = self
}
Either of these methods will keep the target intact. I was having this same issue.
It's still a weird issue and I think the compiler should yell at you for trying to use self before initialization. It does so when you put self() instead.

UIActivityIndicatorView disappears in CollectionView Footer

I have a collectionView with only 1 section in my app which download data from API. I have a pagination and I am trying to add a loading footer in my collectionView. The header appears normally. I have in this footer cell an UIActivityIndicatorView and a UILabel. When the first at a limit is triggered, the 2 elements are present in the cell but when the second limit is triggered, the UIActivityIndicatorView is absent.
Have you an idea for that.
The code of the cell (BaseCell is just a class to avoid tapping the init and required init each time):
class loadingCell: BaseCell {
override func setupViews() {
super.setupViews()
backgroundColor = .yellow
let activity = UIActivityIndicatorView()
activity.backgroundColor = .red
activity.startAnimating()
activity.frame = CGRect(x: 10, y: 20, width: 20, height: 20)
let label = UILabel()
label.text = "hello"
label.frame = CGRect(x: 100, y: 20, width: 40, height: 20)
label.backgroundColor = .green
addSubview(activity)
addSubview(label)
}
}
The collection delegate methods :
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: SCREENW, height: 50)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionFooter {
let loadingFooterView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: loadingCell, for: indexPath)
return loadingFooterView
}
return UICollectionReusableView()
}
The cell is well registered.
What happens when first limit is triggered:
And with the second:
Based on #MaksymMusiienko comment, I have tried this which do the job to reset the animation of the spinner.
class loadingCell: BaseCell {
let activitySpinner: UIActivityIndicatorView = {
let spinner = UIActivityIndicatorView()
spinner.backgroundColor = .red
spinner.startAnimating()
spinner.frame = CGRect(x: 10, y: 20, width: 20, height: 20)
return spinner
}()
override func setupViews() {
super.setupViews()
backgroundColor = .yellow
let label = UILabel()
label.text = "hello"
label.frame = CGRect(x: 100, y: 20, width: 40, height: 20)
label.backgroundColor = .green
addSubview(activitySpinner)
addSubview(label)
}
override func prepareForReuse() {
super.prepareForReuse()
activitySpinner.startAnimating()
}
}

Resources