UICollectionViewCell's UiTextField, overlapping in UICollectionViewController - ios

I am trying to design a multistep sign-up menu. For this purpose I am using UICollectionViewController with screen size cells. In these cells, I have a UITextView to ask questions and a UITextField to collect the answers. I also have a Page object for passing in information from uicollectionviewcontroller upon setting.
The problem I'm having now is that after every 3rd page my textField input from 3 pages ago repeats, instead of showing the placeholder. I have noticed yet another problem, the cells seem to be instantiating just 3 times, and not 6 times for how many pages I have. The instantiation order is very odd too. At first it does it once, then upon button click, twice more, then never again.
How can fix this, I am really struggling with this and I have no idea what's going wrong.
This is my code:
import UIKit
class OnboardingPageViewCell: UICollectionViewCell{
override init(frame: CGRect) {
super.init(frame: frame)
print("made a page")
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var oboardingPage = NewOnboardingPage() {
didSet{
reload()
}
}
private var questionTextField: UITextView = {
var q = UITextView()
q.textColor = UIColor.white
q.textAlignment = .left
q.font = UIFont(name: "Avenir-Black", size: 25)
q.isEditable = true
q.isScrollEnabled = false
q.backgroundColor = UIColor.black
q.translatesAutoresizingMaskIntoConstraints = false
print("made aquestion field")
return q
}()
private var answerField : CustomTextField = {
let tf = CustomTextField.nameField
print("made an answer field")
return tf
}()
private func setupView(){
backgroundColor = UIColor.white
addSubview(questionTextField)
questionTextField.topAnchor.constraint(equalTo: topAnchor, constant: 120).isActive = true
questionTextField.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
questionTextField.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.90).isActive = true
questionTextField.heightAnchor.constraint(equalToConstant: 90).isActive = true
addSubview(answerField)
answerField.topAnchor.constraint(equalTo: questionTextField.bottomAnchor, constant: 20).isActive = true
answerField.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
answerField.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.90).isActive = true
answerField.heightAnchor.constraint(equalToConstant: 90).isActive = true
}
private func reload(){
questionTextField.text = oboardingPage.question
answerField.placeholder = oboardingPage.answerField
}
}
class NewOnboardingPage {
var question : String?
var answerField : String?
}
import UIKit
class SignUpController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
private let cellId = "cellId"
private var pages = [NewOnboardingPage]()
override func viewDidLoad() {
super .viewDidLoad()
setupSignUpControllerView()
addPages()
}
private func addPages(){
let namePage = NewOnboardingPage()
namePage.question = "What's your name?"
namePage.answerField = "What's your name?"
pages.append(namePage)
let birthDayPage = NewOnboardingPage()
birthDayPage.question = "When's your birthdate?"
birthDayPage.answerField = "When's your birthdate?"
pages.append(birthDayPage)
let userNamePage = NewOnboardingPage()
userNamePage.question = "Choose a user name."
userNamePage.answerField = "Choose a user name."
pages.append(userNamePage)
let passWordPage = NewOnboardingPage()
passWordPage.question = "Set a password"
passWordPage.answerField = "Set a password"
pages.append(passWordPage)
let emailAuthPage = NewOnboardingPage()
emailAuthPage.question = "What's your email?"
emailAuthPage.answerField = "What's your email?"
pages.append(emailAuthPage)
let phoneNumberPage = NewOnboardingPage()
phoneNumberPage.question = "What's your phone number?"
phoneNumberPage.answerField = "What's your phone number?"
pages.append(phoneNumberPage)
}
private func setupSignUpControllerView(){
collectionView?.backgroundColor = .white
collectionView?.register(OnboardingPageViewCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.isPagingEnabled = true
collectionView?.isScrollEnabled = true
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
}
view.addSubview(nextButton)
nextButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 400).isActive = true
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 250).isActive = true
nextButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
}
private let nextButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor.RED
button.setTitle("next", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir-Black", size: 25)
button.layer.cornerRadius = 30
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(turnNextPage), for: .touchUpInside)
return button
}()
#objc private func turnNextPage() {
let visibleItems: NSArray = collectionView?.indexPathsForVisibleItems as! NSArray
let currentItem: IndexPath = visibleItems.object(at: 0) as! IndexPath
let nextItem: IndexPath = IndexPath(item: currentItem.item + 1, section: 0)
if nextItem.row < pages.count {
collectionView?.scrollToItem(at: nextItem, at: .left, animated: true)
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pages.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! OnboardingPageViewCell
cell.oboardingPage = pages[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
}
import UIKit
class CustomTextField: UITextField, UITextFieldDelegate {
convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
self.allowsEditingTextAttributes = false
self.autocorrectionType = .no
self.tintColor = UIColor.RED
self.translatesAutoresizingMaskIntoConstraints = false
}
override func willMove(toSuperview newSuperview: UIView?) {
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
editingChanged(self)
}
#objc func editingChanged(_ textField: UITextField) {
guard let text = textField.text else { return }
textField.text = String(text.prefix(30))
}
override func selectionRects(for range: UITextRange) -> [Any] {
return []
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(paste(_:)) ||
action == #selector(cut(_:)) ||
action == #selector(copy(_:)) ||
action == #selector(select(_:)) ||
action == #selector(selectAll(_:)){
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! OnboardingPageViewCell
cell.answerField.text = nil
cell.oboardingPage = pages[indexPath.item]
return cell
}

1- textFeild showing same data instead of placeholder bacause of cell dequeuing so you must hook these properties and clear their content in cellForRowAt
2- Instantiation is 3 not 6 aslo cell dequeuing
Solve:
Add two properties to your model NewOnboardingPage name them currentQuestion and currentAnswer and as the user inputs and scroll to next page save them in the modelarray that you should make global to be accessed indside cell and outside set these values to the textfeild and textView as you scroll in cellForRowAt

Related

How to pressed a UIButton within a customized TableviewCell?

I have been looking all throughout SO on how to interact with a UIButton within a customized tableview cell. All of the answers I have seen are using IBOutlets, however I have not seen a way to do this fully programmatically. I am use to interacting with buttons via button.addTarget. Here are my two ViewControllers, one being the customized tableviewcell and the other being the ViewController.
Here is my customized. I tried using a protocol delegate route, however this has failed.
import UIKit
#objc protocol TableViewNew {
func onClickCell()
}
class NewMoveTableViewCell: UITableViewCell {
var cellDelegate: TableViewNew?
static let identifier = "NewTableViewCell"
private let myImageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
imageView.backgroundColor = .purple
imageView.layer.cornerRadius = 80/2
return imageView
}()
private let myLabel : UILabel = {
let label = UILabel()
label.text = "test"
label.backgroundColor = .blue
label.textColor = .systemPink
label.adjustsFontSizeToFitWidth = true
label.textAlignment = .center
return label
}()
private let button: UIButton = {
let button = UIButton()
button.setTitle("Invite", for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 10
return button
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(myImageView)
addSubview(myLabel)
addSubview(button)
setImageConstratins()
setTitleLabelConstraints()
setButton()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setImageConstratins() {
myImageView.translatesAutoresizingMaskIntoConstraints = false
myImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
myImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12).isActive = true
myImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
myImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
func setTitleLabelConstraints() {
myLabel.translatesAutoresizingMaskIntoConstraints = false
myLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
myLabel.leadingAnchor.constraint(equalTo: myImageView.trailingAnchor, constant: 5).isActive = true
myLabel.heightAnchor.constraint(equalToConstant: 80).isActive = true
//myLabel.trailingAnchor.constraint(equalTo: button.leadingAnchor, constant: -12).isActive = true
}
func setButton() {
button.translatesAutoresizingMaskIntoConstraints = false
button.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
button.leadingAnchor.constraint(equalTo: myLabel.trailingAnchor, constant: -5).isActive = true
button.heightAnchor.constraint(equalToConstant: 80).isActive = true
button.widthAnchor.constraint(equalToConstant: 150).isActive = true
button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12).isActive = true
}
public func configure(with name: String, label: String) {
myLabel.text = label
myImageView.image = UIImage(named: name)
}
override func prepareForReuse() {
super.prepareForReuse()
myLabel.text = nil
myImageView.image = nil
}
#objc func didTapButton(_ sender: Any) {
cellDelegate?.onClickCell()
}
}
Secondly, here is the ViewController that the TableView is within.
import UIKit
class NewMoveViewController: UIViewController {
private let tableView: UITableView = {
let tableView = UITableView()
tableView.rowHeight = 100
return tableView
}()
private var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 50, height: 50)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView?.register(NewMoveCollectionViewCell.self, forCellWithReuseIdentifier: NewMoveCollectionViewCell.identifier)
collectionView?.showsHorizontalScrollIndicator = false
title = "Add to Group"
tableView.register(NewMoveTableViewCell.self, forCellReuseIdentifier: NewMoveTableViewCell.identifier)
tableView.delegate = self
tableView.dataSource = self
collectionView?.backgroundColor = .systemBlue
collectionView?.dataSource = self
collectionView?.delegate = self
guard let myCollection = collectionView else {
return
}
view.addSubview(myCollection)
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView?.frame = CGRect(x: 0, y: 100, width: view.frame.size.width, height: 50)
tableView.frame = CGRect(x: 0, y: 200, width: view.frame.size.width, height: view.frame.size.height)
}
}
extension NewMoveViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: NewMoveTableViewCell.identifier, for: indexPath) as! NewMoveTableViewCell
cell.cellDelegate = self
cell.configure(with: "", label: "test")
return cell
}
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return false
}
}
extension NewMoveViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NewMoveCollectionViewCell.identifier, for: indexPath) as! NewMoveCollectionViewCell
return cell
}
}
extension NewMoveViewController : TableViewNew {
func onClickCell() {
print("Pressed")
}
I conformed this ViewController to the protocol from the customized cell and put the function within the cell's cellForRowAt function. When I use this route, I run my app and everything comes up fine, however when I try to click on the customized tableviewcell within the viewcontroller, nothing happens. Any help would be greatly appreciated.
you need to add the action handler to your button:
button.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)

How to add addTarget for Button in UICollectionView?

I'm a newbie, I have the following problem. There is a screen like this picture. I use UICollectionViewCell for header and I can't addTarget for the blue button in this.
I can’t manage. Could you help me?
class UserProfileVC: UICollectionViewController, UICollectionViewDelegateFlowLayout,UserProfileHeaderDelegate{
var currentUser: User?
var userToLoadFromSearchVC: User?
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
// resgiter header class before use
self.collectionView!.register(UserProfileHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader , withReuseIdentifier: headerIdentifier)
// back ground color
self.collectionView?.backgroundColor = .white
//fetch user data
if userToLoadFromSearchVC == nil{
fetchCurrentUserData()
}
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return 0
}
// config size for header
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// Declare header
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! UserProfileHeader
// set delegate
header.delegate = self
if let user = self.currentUser {
header.user = user
} else if let userToLoadFromSearchVC = self.userToLoadFromSearchVC {
header.user = userToLoadFromSearchVC
self.navigationItem.title = userToLoadFromSearchVC.username
}
// Return header
return header
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
This is my code in header file.
class UserProfileHeader: UICollectionViewCell {
var delegate: UserProfileHeaderDelegate?
var user: User? {
didSet {
configuredEditProfileFollowButton()
setUserStats(for: user)
let fullName = user?.name
nameLabel.text = fullName
guard let profileImageUrl = user?.profileImage else {return}
profileImageView.loadImage(with:profileImageUrl)
}
}
let profileImageView : UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.backgroundColor = .lightGray
return iv
}()
let nameLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 12)
return label
}()
let postLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textAlignment = .center
let attributedText = NSMutableAttributedString(string:"5\n",attributes:[NSAttributedString.Key.font:UIFont.boldSystemFont(ofSize: 14)])
attributedText.append(NSAttributedString(string:"posts",attributes: [NSAttributedString.Key.font:UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor:UIColor.lightGray]))
label.attributedText = attributedText
return label
}()
let followersLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
let followingLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textAlignment = .center
let attributedText = NSMutableAttributedString(string:"5\n",attributes:[NSAttributedString.Key.font:UIFont.boldSystemFont(ofSize: 14)])
attributedText.append(NSAttributedString(string:"following",attributes:[NSAttributedString.Key.font:UIFont.boldSystemFont(ofSize: 14), NSAttributedString.Key.foregroundColor:UIColor.lightGray]))
label.attributedText = attributedText
return label
}()
let editProfileFollowButton : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Loading", for: .normal)
button.layer.cornerRadius = 5
button.layer.borderColor = UIColor.lightGray.cgColor
button.layer.borderWidth = 0.5
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(handleEditProfileFollow), for: .touchUpOutside)
return button
}()
let gridButton : UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named: "grid"), for: .normal)
return button
}()
let listButton : UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named:"list"), for: .normal)
button.tintColor = UIColor(white: 0, alpha: 0.2)
return button
}()
let bookmarkButton : UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named:"ribbon"), for: .normal)
button.tintColor = UIColor(white: 0, alpha: 0.2)
button.addTarget(self, action: #selector(testFunc(_:)), for: UIControl.Event.touchUpInside)
return button
}()
#objc func testFunc(_ sender : UIButton){
print("Pressed ")
}
#objc func handleFollowersTapped() {
delegate?.handleFollowersTapped(for: self)
}
#objc func handleFollowingTapped() {
delegate?.handleFollowingTapped(for: self)
}
#objc func handleEditProfileFollow() {
guard let user = self.user else {return}
if editProfileFollowButton.titleLabel?.text == "Edit Profile"{
print("Handler edit profile ")
}
else{
if editProfileFollowButton.titleLabel?.text == "Follow"{
editProfileFollowButton.setTitle("Following", for: .normal)
user.follow()
}else{
editProfileFollowButton.setTitle("Follow", for: .normal)
user.unfollow()
}
}
}
This is because you are creating the button target before the UserProfileHeader initialized. So you need to create the button using lazy var (lazily).
private lazy var button: UIButton = {
let button = UIButton()
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(handleButtonTapped), for: .touchUpInside)
return button
}()
#objc private func handleButtonTapped() {
print("Button tapped")
}
Try this, i think this will help you.
class customCell: UICollectionViewCell {
#IBOutlet weak var btn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: customCell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) as! customCell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: #selector(self.btnpressed(sender:)), for: .touchUpInside)
return cell
}
#objc func btnpressed(sender: UIButton!) {
print(sender.tag)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: customCell, for: indexPath) as! customCell
view.pagePluginButtonAction = {
self.TapedBtn()
}
return view
}
func TapedBtn(){
print("click")
}
You need to add the target in 'viewForSupplementaryElementOfKind' where you set up your header. See example below, just after you set the header delegate.
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// Declare header
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! UserProfileHeader
// set delegate
header.delegate = self
// Add the target here
header.yourButton.addTarget(self, action: #selector(handleYourButton), for: .touchUpInside)
if let user = self.currentUser {
header.user = user
} else if let userToLoadFromSearchVC = self.userToLoadFromSearchVC {
header.user = userToLoadFromSearchVC
self.navigationItem.title = userToLoadFromSearchVC.username
}
// Return header
return header
}

Invalid Selector Using Delegate Pattern

I am attempting to use the delegate pattern to animate a change in height for a collectionView. The button that triggers this change is in the header. However when I press the button not only does the height not change but it also crashes with the error
'NSInvalidArgumentException', reason: '-[UIButton length]: unrecognized selector sent to instance 0x12f345b50'
I feel like I have done everything right but it always crashes when I click the button. Does anyone see anything wrong and is there anyway that I can animate the change in height for the cell the way I want it to. This is the cell class along with the protocol and the delegate.
import Foundation
import UIKit
protocol ExpandedCellDelegate:NSObjectProtocol{
func viewEventsButtonTapped(indexPath:IndexPath)
}
class EventCollectionCell:UICollectionViewCell {
var headerID = "headerID"
weak var delegateExpand:ExpandedCellDelegate?
public var indexPath:IndexPath!
var eventArray = [EventDetails](){
didSet{
self.eventCollectionView.reloadData()
}
}
var enentDetails:Friend?{
didSet{
var name = "N/A"
var total = 0
seperator.isHidden = true
if let value = enentDetails?.friendName{
name = value
}
if let value = enentDetails?.events{
total = value.count
self.eventArray = value
seperator.isHidden = false
}
if let value = enentDetails?.imageUrl{
profileImageView.loadImage(urlString: value)
}else{
profileImageView.image = imageLiteral(resourceName: "Tokyo")
}
self.eventCollectionView.reloadData()
setLabel(name: name, totalEvents: total)
}
}
let container:UIView={
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 16
view.layer.borderColor = UIColor.lightGray.cgColor
view.layer.borderWidth = 0.3
return view
}()
//profile image view for the user
var profileImageView:CustomImageView={
let iv = CustomImageView()
iv.layer.masksToBounds = true
iv.layer.borderColor = UIColor.lightGray.cgColor
iv.layer.borderWidth = 0.3
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
//will show the name of the user as well as the total number of events he is attending
let labelNameAndTotalEvents:UILabel={
let label = UILabel()
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
return label
}()
let seperator:UIView={
let view = UIView()
view.backgroundColor = .lightGray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
//collectionview that contains all of the events a specific user will be attensing
lazy var eventCollectionView:UICollectionView={
let flow = UICollectionViewFlowLayout()
flow.scrollDirection = .vertical
let spacingbw:CGFloat = 5
flow.minimumLineSpacing = 0
flow.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: flow)
//will register the eventdetailcell
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = .white
cv.register(EventDetailsCell.self, forCellWithReuseIdentifier: "eventDetails")
cv.register(FriendsEventsViewHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerID)
cv.delegate = self
cv.dataSource = self
cv.backgroundColor = .blue
cv.contentInset = UIEdgeInsetsMake(spacingbw, 0, spacingbw, 0)
cv.showsVerticalScrollIndicator = false
cv.bounces = false
return cv
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.setUpCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setLabel(name:String,totalEvents:Int){
let mainString = NSMutableAttributedString()
let attString = NSAttributedString(string:name+"\n" , attributes: [NSAttributedStringKey.foregroundColor:UIColor.black,NSAttributedStringKey.font:UIFont.systemFont(ofSize: 14)])
mainString.append(attString)
let attString2 = NSAttributedString(string:totalEvents == 0 ? "No events" : "\(totalEvents) \(totalEvents == 1 ? "Event" : "Events")" , attributes: [NSAttributedStringKey.foregroundColor:UIColor.darkGray,NSAttributedStringKey.font:UIFont.italicSystemFont(ofSize: 12)])
mainString.append(attString2)
labelNameAndTotalEvents.attributedText = mainString
}
}
//extension that handles creation of the events detail cells as well as the eventcollectionview
//notice the delegate methods
//- Mark EventCollectionView DataSource
extension EventCollectionCell:UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return eventArray.count
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! FriendsEventsViewHeader
header.viewEventsButton.addTarget(self, action: #selector(viewEventsButtonTapped), for: .touchUpInside)
return header
}
#objc func viewEventsButtonTapped(indexPath:IndexPath){
print("View events button touched")
if let delegate = self.delegateExpand{
delegate.viewEventsButtonTapped(indexPath: indexPath)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"eventDetails" , for: indexPath) as! EventDetailsCell
cell.details = eventArray[indexPath.item]
cell.backgroundColor = .yellow
cell.seperator1.isHidden = indexPath.item == eventArray.count-1
return cell
}
}
//- Mark EventCollectionView Delegate
extension EventCollectionCell:UICollectionViewDelegateFlowLayout{
//size for each indvidual cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 50)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 40)
}
}
This is the view that ultimately is supposed to be handling the expansion via the delegate function.
import UIKit
import Firebase
class FriendsEventsView: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
var friends = [Friend]()
var followingUsers = [String]()
var notExpandedHeight : CGFloat = 100
var expandedHeight : CGFloat?
var isExpanded = [Bool]()
//so this is the main collectonview that encompasses the entire view
//this entire view has eventcollectionCell's in it which in itself contain a collectionview which also contains cells
//so I ultimately want to shrink the eventCollectionView
lazy var mainCollectionView:UICollectionView={
// the flow layout which is needed when you create any collection view
let flow = UICollectionViewFlowLayout()
//setting the scroll direction
flow.scrollDirection = .vertical
//setting space between elements
let spacingbw:CGFloat = 5
flow.minimumLineSpacing = spacingbw
flow.minimumInteritemSpacing = 0
//actually creating collectionview
let cv = UICollectionView(frame: .zero, collectionViewLayout: flow)
//register a cell for that collectionview
cv.register(EventCollectionCell.self, forCellWithReuseIdentifier: "events")
cv.translatesAutoresizingMaskIntoConstraints = false
//changing background color
cv.backgroundColor = .red
//sets the delegate of the collectionView to self. By doing this all messages in regards to the collectionView will be sent to the collectionView or you.
//"Delegates send messages"
cv.delegate = self
//sets the datsource of the collectionView to you so you can control where the data gets pulled from
cv.dataSource = self
//sets positon of collectionview in regards to the regular view
cv.contentInset = UIEdgeInsetsMake(spacingbw, 0, spacingbw, 0)
return cv
}()
//label that will be displayed if there are no events
let labelNotEvents:UILabel={
let label = UILabel()
label.textColor = .lightGray
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = UIFont.italicSystemFont(ofSize: 14)
label.text = "No events found"
label.isHidden = true
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
//will set up all the views in the screen
self.setUpViews()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: imageLiteral(resourceName: "close_black").withRenderingMode(.alwaysOriginal), style: .done, target: self, action: #selector(self.goBack))
}
func setUpViews(){
//well set the navbar title to Friends Events
self.title = "Friends Events"
view.backgroundColor = .white
//adds the main collection view to the view and adds proper constraints for positioning
view.addSubview(mainCollectionView)
mainCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
mainCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
mainCollectionView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
mainCollectionView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
//adds the label to alert someone that there are no events to the collectionview and adds proper constrains for positioning
mainCollectionView.addSubview(labelNotEvents)
labelNotEvents.centerYAnchor.constraint(equalTo: mainCollectionView.centerYAnchor, constant: 0).isActive = true
labelNotEvents.centerXAnchor.constraint(equalTo: mainCollectionView.centerXAnchor, constant: 0).isActive = true
//will fetch events from server
self.fetchEventsFromServer()
}
// MARK: CollectionView Datasource for maincollection view
//will let us know how many eventCollectionCells tht contain collectionViews will be displayed
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(friends.count)
isExpanded = Array(repeating: false, count: friends.count)
return friends.count
}
//will control the size of the eventCollectionCells that contain collectionViews
height is decided for the collectionVIew here
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let event = friends[indexPath.item]
if let count = event.events?.count,count != 0{
notExpandedHeight += (CGFloat(count*40)+10)
}
self.expandedHeight = notExpandedHeight
if isExpanded[indexPath.row] == true{
return CGSize(width: collectionView.frame.width, height: expandedHeight!)
}else{
return CGSize(width: collectionView.frame.width, height: 100)
}
}
//will do the job of effieicently creating cells for the eventcollectioncell that contain eventCollectionViews using the dequeReusableCells function
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "events", for: indexPath) as! EventCollectionCell
cell.backgroundColor = UIColor.orange
cell.indexPath = indexPath
cell.delegateExpand = self
cell.enentDetails = friends[indexPath.item]
return cell
}
}
extension FriendsEventsView:ExpandedCellDelegate{
func viewEventsButtonTapped(indexPath:IndexPath) {
isExpanded[indexPath.row] = !isExpanded[indexPath.row]
print(indexPath)
UIView.animate(withDuration: 0.8, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseInOut, animations: {
self.mainCollectionView.reloadItems(at: [indexPath])
}, completion: { success in
print("success")
})
}
}
I used this post for reference to implement
Expandable UICollectionViewCell
This is a very common mistake.
The passed parameter in a target / action selector is always the affected UI element which triggers the action in your case the button.
You cannot pass an arbitrary object for example an indexPath because there is no parameter in the addTarget method to specify that arbitrary object.
You have to declare the selector
#objc func viewEventsButtonTapped(_ sender: UIButton) {
or without a parameter
#objc func viewEventsButtonTapped() {
UIControl provides a third syntax
#objc func viewEventsButtonTapped(_ sender: UIButton, withEvent event: UIEvent?) {
Any other syntax is not supported.

Inset a new section in UICollectionView with new type of Cell

I am working on a chat app. I am using UICollectionView to display text and different type of text. I have 3 type of cells. In the first section, I am loading the first type of cell. in second, second type and in third, third type of cell loading. I have a button text field. When i click send button in text field i want to create new section of type first cell. I don't know how to create. Please help :)
Here is my Code:
// ChatLogController.swift
// Blubyn
//
// Created by JOGENDRA on 02/02/18.
// Copyright © 2018 Jogendra Singh. All rights reserved.
//
import UIKit
fileprivate enum DefaultConstants {
static let sendButtonImageName: String = "send-icon"
static let voiceButtonImageName: String = "microphone"
}
enum Cells {
case chatCell
case oneWayFlight
case twoWayFlight
}
class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate var sideBar = SideBar()
lazy var inputTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Send a message..."
textField.delegate = self
return textField
}()
let textView: UIView = {
let textFieldview = UIView()
textFieldview.backgroundColor = UIColor.white
textFieldview.translatesAutoresizingMaskIntoConstraints = false
return textFieldview
}()
let cellId = "cellId"
let oneWayCellId = "oneWayFlightCell"
let twoWayCellId = "twoWayFlightCell"
var numberOfSections: Int = 0
var numberOfItemsInASection: Int = 0
var cellType: Cells?
var keyboardHeight: CGFloat = 0.0
var textViewBottomAnchor: NSLayoutConstraint?
var userMessages: [String] = ["Hey there!", "I want to book flight for Pokhara, Nepal", "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.", "Book a hotel for me near lakeside", "book returning flight"]
var systemMessages: [String] = ["Hello Jogendra!", "Pluto at your service - your guide and concierge to help you with the planning ticket booking and finding new and exotic places.", "Go on! Try me out. Won't take long. I promise."]
lazy var messages: [String] = systemMessages + userMessages
override func viewDidLoad() {
super.viewDidLoad()
setupInputComponents()
sideBarSetup()
collectionView?.contentInset = UIEdgeInsets(top: 8.0, left: 0, bottom: 52.0, right: 0)
collectionView?.backgroundColor = UIColor.chatbackgroundColor
// Register Chat Cell
collectionView?.register(ChatMessagesCell.self, forCellWithReuseIdentifier: cellId)
// Regsiter One Way Flight Cell
let oneWayFlightCellNib = UINib(nibName: "OneWayFlightViewCell", bundle: nil)
collectionView?.register(oneWayFlightCellNib, forCellWithReuseIdentifier: oneWayCellId)
// Register Two Way Flight Cell
let twoWayFlightCellNib = UINib(nibName: "TwoWayFlightViewCell", bundle: nil)
collectionView?.register(twoWayFlightCellNib, forCellWithReuseIdentifier: twoWayCellId)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
// Register Notification, To know When Key Board Appear.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: Notification.Name.UIKeyboardWillShow, object: nil)
// Register Notification, To know When Key Board Hides.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
// De register the notifications
NotificationCenter.default.removeObserver(self)
}
fileprivate func setupInputComponents() {
// Text View setups
view.addSubview(textView)
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
textView.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
textViewBottomAnchor = textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
textViewBottomAnchor?.isActive = true
let voiceButton = UIButton(type: .system)
let voiceButtonImage = UIImage(named: DefaultConstants.voiceButtonImageName)
voiceButton.setImage(voiceButtonImage, for: .normal)
textView.addSubview(voiceButton)
voiceButton.translatesAutoresizingMaskIntoConstraints = false
voiceButton.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
voiceButton.trailingAnchor.constraint(equalTo: textView.trailingAnchor).isActive = true
voiceButton.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
voiceButton.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
let sendButton = UIButton(type: .system)
let sendButtonImage = UIImage(named: DefaultConstants.sendButtonImageName)
sendButton.setImage(sendButtonImage, for: .normal)
textView.addSubview(sendButton)
sendButton.addTarget(self, action: #selector(didTapSend), for: .touchUpInside)
sendButton.translatesAutoresizingMaskIntoConstraints = false
sendButton.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
sendButton.trailingAnchor.constraint(equalTo: voiceButton.leadingAnchor).isActive = true
sendButton.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
sendButton.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
textView.addSubview(inputTextField)
inputTextField.translatesAutoresizingMaskIntoConstraints = false
inputTextField.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 4.0).isActive = true
inputTextField.trailingAnchor.constraint(equalTo: sendButton.leadingAnchor, constant: -4.0).isActive = true
inputTextField.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
inputTextField.bottomAnchor.constraint(equalTo: textView.safeAreaLayoutGuide.bottomAnchor).isActive = true
let separator = UIView()
separator.backgroundColor = UIColor.black.withAlphaComponent(0.4)
textView.addSubview(separator)
separator.translatesAutoresizingMaskIntoConstraints = false
separator.leadingAnchor.constraint(equalTo: textView.leadingAnchor).isActive = true
separator.trailingAnchor.constraint(equalTo: textView.trailingAnchor).isActive = true
separator.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
separator.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
}
// MARK: - Keyboard Events
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo![UIKeyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
keyboardHeight = keyboardRectangle.height
}
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
textViewBottomAnchor?.constant = -keyboardHeight
UIView.animate(withDuration: keyboardDuration!, animations: {
self.view.layoutIfNeeded()
})
}
#objc func keyboardWillHide(_ notification: Notification) {
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
textViewBottomAnchor?.constant = 0
UIView.animate(withDuration: keyboardDuration!, animations: {
self.view.layoutIfNeeded()
})
}
// MARK: - Collection View Methods
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return messages.count
case 1:
numberOfItemsInASection = 5
return numberOfItemsInASection
case 2:
return 5
default:
numberOfItemsInASection = 5
return numberOfItemsInASection
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessagesCell
let message = messages[indexPath.item]
cell.chatTextView.text = message
// Align chat cell according
if userMessages.contains(message) {
cell.bubbleView.backgroundColor = UIColor.white
cell.chatTextView.textColor = UIColor.black
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
} else {
cell.bubbleView.backgroundColor = UIColor.chatThemeColor
cell.chatTextView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}
//Modify the width accordingly
cell.bubbleWidthAnchor?.constant = estimateFrameForText(text: message).width + 32.0
if indexPath.section == 0 {
cellType = Cells.chatCell
return cell
} else if indexPath.section == 1 {
let oneWayFlightCell = collectionView.dequeueReusableCell(withReuseIdentifier: oneWayCellId, for: indexPath) as! OneWayFlightViewCell
cellType = Cells.oneWayFlight
return oneWayFlightCell
} else {
let twoWayFlightCell = collectionView.dequeueReusableCell(withReuseIdentifier: twoWayCellId, for: indexPath) as! TwoWayFlightViewCell
cellType = Cells.twoWayFlight
return twoWayFlightCell
}
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
numberOfSections = 3
return numberOfSections
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var cellHeight: CGFloat = 80.0
let text = messages[indexPath.item]
cellHeight = estimateFrameForText(text: text).height + 20.0
if indexPath.section == 1 {
cellHeight = 112
} else if indexPath.section == 2 {
cellHeight = 201
}
return CGSize(width: collectionView.frame.width, height: cellHeight)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
inputTextField.resignFirstResponder()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
//{top, left, bottom, right}
return UIEdgeInsetsMake(10, 0, 10, 0)
}
private func estimateFrameForText(text: String) -> CGRect {
let size = CGSize(width: 300.0, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17.0)], context: nil)
}
#objc fileprivate func didTapSend() {
if let enteredText = inputTextField.text, !enteredText.isEmpty {
messages.append(enteredText)
userMessages.append(enteredText)
}
collectionView?.reloadData()
inputTextField.text = nil
}
fileprivate func sideBarSetup() {
sideBar = SideBar(sourceView: self.view, menuItems: ["Chat", "Hot Deals", "My Trips", "Experiences", "Settings", "Profile"])
sideBar.delegate = self
}
#IBAction func didTapMenu(_ sender: Any) {
sideBar.showSideBar(!sideBar.isSideBarOpen)
}
#IBAction func didTapHelp(_ sender: Any) {
}
}
extension ChatLogController: SideBarDelegate {
func SideBarDidSelectButtonAtIndex(_ index: Int) {
switch index {
case 0:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 1:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 2:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 3:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 4:
let settingStoryboard = UIStoryboard(name: "Main", bundle: nil)
let settingsViewController = settingStoryboard.instantiateViewController(withIdentifier: "settingvc")
self.navigationController?.pushViewController(settingsViewController, animated: true)
case 5:
let profileStoryboard = UIStoryboard(name: "Main", bundle: nil)
let profileViewController = profileStoryboard.instantiateViewController(withIdentifier: "profilevc")
self.navigationController?.pushViewController(profileViewController, animated: true)
default:
break
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
inputTextField.resignFirstResponder()
inputTextField.endEditing(true)
}
}
extension ChatLogController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
inputTextField.endEditing(true)
return true
}
}
Designs:
See Screens Section of [this link][1].
Achieved Designs:
[![screenshot1][2]][2]
[![screenshot2][3]][3]
[![screenshot3][4]][4]
[![screenshot4][5]][5]
[1]: https://blubyn.com/
[2]: https://i.stack.imgur.com/S9ZLX.png
[3]: https://i.stack.imgur.com/wLvAu.png
[4]: https://i.stack.imgur.com/nBKbH.png
[5]: https://i.stack.imgur.com/Sota4.png

UILabel text not updating even though it has new value, have tried everything

I am using UICollectionView didSelectItemAt to update a UI label that I set up in my HomeController. So basically when I press the cell I want my text to be updated. However the text doesn't update, I have debugged though and the value changes. I have tried everything, both setNeedsDisplay() and running through main thread (which it already does)
I have quite a lot of code in these classes (I don't use storyboard) but this is the label setup (sits in HomeController):
import UIKit
import CoreData
class mainHomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
static let sharedInstance = HomeController()
override func viewDidLoad() {
super.viewDidLoad()
setupBasketBar()
}
let totNumber: UILabel = {
let label = UILabel()
label.text = "0"
label.numberOfLines = 2
return label
}()
func setupBasketBar() {
self.view.addSubview(totNumber)
totNumber.translatesAutoresizingMaskIntoConstraints = false
totNumber.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 330).isActive = true
totNumber.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totNumber.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totNumber.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 5).isActive = true
}
}
and this sits in the feed cell:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
HomeController.sharedInstance.totNumber.text = ("234")
HomeController.sharedInstance.totNumber.setNeedsDisplay()
}
I have edited out the relevant parts.
This is the whole code for the HomeController:
import UIKit
import CoreData
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
static let sharedInstance = HomeController()
let cellId = "cellId"
let trendingCellId = "trendingCellId"
let subscriptionCellId = "subscriptionCellId"
let titles = ["Home", "Trending", "Subscriptions", "Account"]
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isTranslucent = false
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: view.frame.height))
titleLabel.text = "Home"
titleLabel.textColor = UIColor.black
titleLabel.font = UIFont.systemFont(ofSize: 20)
navigationItem.titleView = titleLabel
setupCollectionView()
setupMenuBar()
setupBasketBar()
}
func setupCollectionView() {
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
}
collectionView?.backgroundColor = UIColor.white
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.register(TrendingCell.self, forCellWithReuseIdentifier: trendingCellId)
collectionView?.register(SubscriptionCell.self, forCellWithReuseIdentifier: subscriptionCellId)
collectionView?.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.isPagingEnabled = true
}
lazy var settingsLauncher: SettingsLauncher = {
let launcher = SettingsLauncher()
launcher.homeController = self
return launcher
}()
func handleMore() {
//show menu
settingsLauncher.showSettings()
}
func showControllerForSetting(_ setting: Setting) {
let dummySettingsViewController = UIViewController()
dummySettingsViewController.view.backgroundColor = UIColor.white
dummySettingsViewController.navigationItem.title = setting.name.rawValue
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingsViewController, animated: true)
}
func handleSearch() {
scrollToMenuIndex(2)
}
func scrollToMenuIndex(_ menuIndex: Int) {
let indexPath = IndexPath(item: menuIndex, section: 0)
collectionView?.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition(), animated: true)
setTitleForIndex(menuIndex)
}
fileprivate func setTitleForIndex(_ index: Int) {
if let titleLabel = navigationItem.titleView as? UILabel {
titleLabel.text = " \(titles[index])"
}
}
lazy var menuBar: MenuBar = {
let mb = MenuBar()
mb.homeController = self
return mb
}()
func buttonAction(sender: UIButton!) {
let btnsendtag: UIButton = sender
if btnsendtag.tag == 1 {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "NewViewController") as! UINavigationController
self.present(vc, animated: true, completion: nil)
}
}
let totLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let btn: UIButton = UIButton(frame: CGRect(x: 0, y: 600, width: 500, height: 80))
func setupBasketBar() {
//Checkout button
btn.backgroundColor = UIColor.rgb(36, green: 51, blue: 70)
btn.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
btn.tag = 1
self.view.addSubview(btn)
btn.setTitleColor(UIColor.yellow, for: .normal)
//Button that updates the current amount
totLabel.text = "Total amount"
totLabel.textColor = UIColor.white
self.view.addSubview(totLabel)
//constraints
totLabel.translatesAutoresizingMaskIntoConstraints = false
totLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
totLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totLabel.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1).isActive = true
//oldconstraints
/* self.view.addSubview(totNumber)
totNumber.translatesAutoresizingMaskIntoConstraints = false
totNumber.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 330).isActive = true
totNumber.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totNumber.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totNumber.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1).isActive = true*/
}
fileprivate func setupMenuBar() {
navigationController?.hidesBarsOnSwipe = false
let redView = UIView()
redView.backgroundColor = UIColor.rgb(36, green: 51, blue: 70)
view.addSubview(redView)
view.addConstraintsWithFormat("H:|[v0]|", views: redView)
view.addConstraintsWithFormat("V:[v0(50)]", views: redView)
view.addSubview(menuBar)
view.addConstraintsWithFormat("H:|[v0]|", views: menuBar)
view.addConstraintsWithFormat("V:[v0(50)]", views: menuBar)
menuBar.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
}
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let index = targetContentOffset.pointee.x / view.frame.width
let indexPath = IndexPath(item: Int(index), section: 0)
menuBar.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
setTitleForIndex(Int(index))
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier: String
if indexPath.item == 1 {
identifier = trendingCellId
} else if indexPath.item == 2 {
identifier = subscriptionCellId
} else {
identifier = cellId
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height - 50)
}
}
Okay! looking at the updated code snippet the sharedInstance singleton is definitely not needed - I'd remove that completely.
The didSelectItemAt method then just needs to be this:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
totNumber.text = "234"
}
I'm guessing your sharedInstance variable is a new instance of the view controller, this is separate from the one that is allocated and displayed from storyboards or segues. You should set sharedInstance equal to self inside viewDidLoad

Resources