How to add addTarget for Button in UICollectionView? - ios

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
}

Related

Elements of the FirstViewController still visible in DetailViewController after using pushViewController method

I first programmatically created a tableview :
private func setupTableView() {
tableView = UITableView(frame: CGRect(x: 0, y: 180, width: view.frame.width, height: view.frame.height), style: UITableView.Style.plain)
tableView.dataSource = self
tableView.delegate = self
tableView.register(ItemTableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
}
and set the cellForRow method as below :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ItemTableViewCell
guard let finalItems = presenter.finalItems?[indexPath.row] else { return cell }
presenter.configure(cell: cell, FinalItem: finalItems)
return cell
}
Then I configure the ItemTableViewCell as below :
class ItemTableViewCell: UITableViewCell {
private var iconImageView : UIImageView = {
let imgView = UIImageView(image: #imageLiteral(resourceName: "Image"))
imgView.contentMode = .scaleAspectFit
imgView.clipsToBounds = true
return imgView
}()
private var titleLabel : UILabel = {
let lbl = UILabel()
lbl.textColor = .black
lbl.font = UIFont.boldSystemFont(ofSize: 12)
lbl.textAlignment = .left
return lbl
}()
func configure(finalItem: FinalItem) {
titleLabel.text = finalItem.title
iconImageView.downloaded(from: finalItem.images_url.small)
}
}
When I push to the DetailViewController with the uinavigationbar, the elements contained in the rows (titles, labels...) are still visible a few milli seconds:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let finalItem = finalItems[indexPath.row]
let detailViewController = ModuleBuilder.createDetailModuleWith(finalItem)
detailViewController.finalItem = finalItem
navigationController?.pushViewController(detailViewController, animated: true)
}
This is not what I am expecting. I never figure this problem out before.

Dynamically resize TableViewController Cell

In my project I have a SignUpViewController which looks like this:
All the textFields are custom-cells within a tableViewController.
TableView:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 1st cell -> email textfield
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpEmailCell", for: indexPath) as! SignUpEmailCell
return cell
// 2nd cell -> anzeigename
}else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpAnzeigeName", for: indexPath) as! SignUpAnzeigeName
return cell
// 3rd cell -> Wishlist-Handle
}else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpHandleCell", for: indexPath) as! SignUpHandleCell
return cell
// 4th cell -> passwort textfield
}else if indexPath.row == 3 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpPasswordCell", for: indexPath) as! SignUpPasswordCell
return cell
// 5th cell -> repeat password textfield
}else if indexPath.row == 4 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpPasswordRepeatCell", for: indexPath) as! SignUpPasswordRepeatCell
return cell
// 6th cell -> document label
}else if indexPath.row == 5 {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpDocumentCell", for: indexPath) as! SignUpDocumentCell
return cell
}
// last cell -> signUpButton
let cell = tableView.dequeueReusableCell(withIdentifier: "SignUpButtonCell", for: indexPath) as! SignUpButtonCell
return cell
}
Password-Cell: (basic structure is the same for every cell)
class SignUpPasswordCell: UITableViewCell, UITextFieldDelegate {
public static let reuseID = "SignUpPasswordCell"
lazy var eyeButton: UIButton = {
let v = UIButton()
v.addTarget(self, action: #selector(eyeButtonTapped), for: .touchUpInside)
v.setImage(UIImage(named: "eyeOpen"), for: .normal)
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
lazy var passwordTextField: CustomTextField = {
let v = CustomTextField()
v.borderActiveColor = .white
v.borderInactiveColor = .white
v.textColor = .white
v.font = UIFont(name: "AvenirNext-Regular", size: 17)
v.placeholder = "Passwort"
v.placeholderColor = .white
v.placeholderFontScale = 0.8
v.minimumFontSize = 13
v.borderStyle = .line
v.addTarget(self, action: #selector(SignUpPasswordCell.passwordTextFieldDidChange(_:)),for: .editingChanged)
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.backgroundColor = .clear
passwordTextField.delegate = self
eyeButton.isHidden = true
passwordTextField.textContentType = .newPassword
passwordTextField.isSecureTextEntry.toggle()
setupViews()
}
func setupViews(){
contentView.addSubview(passwordTextField)
contentView.addSubview(eyeButton)
passwordTextField.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
passwordTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
passwordTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
passwordTextField.heightAnchor.constraint(equalToConstant: 60).isActive = true
eyeButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -5).isActive = true
eyeButton.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 10).isActive = true
}
var check = true
#objc func eyeButtonTapped(_ sender: Any) {
check = !check
if check == true {
eyeButton.setImage(UIImage(named: "eyeOpen"), for: .normal)
} else {
eyeButton.setImage(UIImage(named: "eyeClosed"), for: .normal)
}
passwordTextField.isSecureTextEntry.toggle()
if let existingText = passwordTextField.text, passwordTextField.isSecureTextEntry {
/* When toggling to secure text, all text will be purged if the user
continues typing unless we intervene. This is prevented by first
deleting the existing text and then recovering the original text. */
passwordTextField.deleteBackward()
if let textRange = passwordTextField.textRange(from: passwordTextField.beginningOfDocument, to: passwordTextField.endOfDocument) {
passwordTextField.replace(textRange, withText: existingText)
}
}
/* Reset the selected text range since the cursor can end up in the wrong
position after a toggle because the text might vary in width */
if let existingSelectedTextRange = passwordTextField.selectedTextRange {
passwordTextField.selectedTextRange = nil
passwordTextField.selectedTextRange = existingSelectedTextRange
}
}
#objc func passwordTextFieldDidChange(_ textField: UITextField) {
if textField.text == "" {
self.eyeButton.isHidden = true
}else {
self.eyeButton.isHidden = false
}
}
}
Problem:
I would like to be able to show some extra information on some textFields when selected.
For example: When passwordTextField is editing I would like to show the password requirements right below the textfield. But the extra information should only be displayed while editing or after editing. When the ViewController is being displayed at first it should still look like the picture above.
I hope my problem is clear and I am grateful for every help.

Adding a target to UIButton in UITableViewCell with didSet

I am trying to refactor my code and I can't seem to active the handleFavoriteStar() action from the SearchController when the button is tapped. I was following this video by LBTA on refactoring: https://youtu.be/F3snOdQ5Qyo
Formula Cell:
class FormulasCell: UITableViewCell {
var searchController: SearchController! {
didSet {
buttonStar.addTarget(searchController, action: #selector(searchController.handleFavoritedStar), for: .touchUpInside)
}
}
var buttonStar: UIButton = {
let button = UIButton()
button.setImage( #imageLiteral(resourceName: "GrayStar") , for: .normal)
button.tintColor = UIColor.greyFormula
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
}
Search Controller:
class SearchController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let formulaCell = FormulasCell()
formulaCell.searchController = self
setupTableView()
}
#objc func handleFavoritedStar() {
print("Added to Favorites")
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! FormulasCell
cell.selectionStyle = .none
cell.searchController = self
return cell
}

UICollectionViewCell's UiTextField, overlapping in UICollectionViewController

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

Custom cell for UICollection view cell unable clear old data

I created a custom UICollection cell but the data sometimes appear in the wrong cell and no matter how much I refresh the UICollection view it refuses to change. I have done a print out to see if the data gotten from the array is wrong but it's not. Is there a way to clear the old data from the cell before inputting the next one. Any suggestion will be appreciated.
custom cell
class customAppointmentViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let tniv = UIImageView()
tniv.translatesAutoresizingMaskIntoConstraints = false
tniv.backgroundColor = UIColor.clear
tniv.contentMode = .scaleAspectFit
return tniv
}()
let seperatorView: UIView = {
let sv = UIView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = UIColor(r: 11, g: 49, b: 68)
return sv
}()
let clientNamePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 17)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let openingTimePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let closingTimePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let bookedBarberNamePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let servicePricePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 10)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .right
return fnhp
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(clientNamePlaceHolder)
addSubview(openingTimePlaceHolder)
addSubview(closingTimePlaceHolder)
addSubview(bookedBarberNamePlaceHolder)
addSubview(servicePricePlaceHolder)
addSubview(seperatorView)
backgroundColor = UIColor(r: 23, g: 69, b: 90)
addContraintsWithFormat(format: "H:|-16-[v0(90)]|", views: thumbnailImageView)
addContraintsWithFormat(format: "H:|-116-[v0][v1(50)]-10-|", views: clientNamePlaceHolder, servicePricePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: openingTimePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: closingTimePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: bookedBarberNamePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0(20)][v1(20)][v2(20)][v3(20)]-10-|", views: clientNamePlaceHolder, openingTimePlaceHolder,closingTimePlaceHolder, bookedBarberNamePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0(20)]|", views: servicePricePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0]-10-[v1(5)]|", views: thumbnailImageView,seperatorView)
addContraintsWithFormat(format: "H:|[v0]|", views: seperatorView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
collection view
extension AppointmentsViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.appointments.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! customAppointmentViewCell
//empty cell data
//real data
cell.openingTimePlaceHolder.text = ""
if let opentime = self.appointments[safe: indexPath.row]?.bookingStartTimeString {
cell.openingTimePlaceHolder.text = opentime
} else {
cell.openingTimePlaceHolder.text = ""
}
cell.closingTimePlaceHolder.text = ""
if let closetime = self.appointments[safe: indexPath.row]?.bookingEndTimeString {
cell.closingTimePlaceHolder.text = closetime
} else {
cell.closingTimePlaceHolder.text = ""
}
cell.bookedBarberNamePlaceHolder.text = ""
if let barberName = self.appointments[safe: indexPath.row]?.bookedBarberName {
cell.bookedBarberNamePlaceHolder.text = barberName
} else {
cell.bookedBarberNamePlaceHolder.text = ""
}
cell.servicePricePlaceHolder.text = ""
if let servicepricee = self.appointments[safe: indexPath.row]?.bookedServicePrice {
cell.servicePricePlaceHolder.text = servicepricee
} else {
cell.servicePricePlaceHolder.text = ""
}
cell.thumbnailImageView.image = UIImage()
if let profileimagess = self.appointments[safe: indexPath.row]?.profileImage {
cell.thumbnailImageView.image = profileimagess
} else {
cell.thumbnailImageView.image = UIImage()
}
cell.clientNamePlaceHolder.text = ""
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
} else {
cell.clientNamePlaceHolder.text = ""
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectView.frame.width, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let uuidAvail = UserDefaults.standard.object(forKey: "theOriginalBarberShopUUID") as? String{
if let bookIDDD = self.appointments[safe: indexPath.row]?.bookingUniqueID {
let orderDetail = OrderDetailViewController()
orderDetail.specificAppintment = self.appointments[indexPath.row]
orderDetail.barberShopID = uuidAvail
orderDetail.bookingUniqueIDDD = bookIDDD
orderDetail.bookedBarberUUIDAX = self.appointments[indexPath.row].bookedBarberUUID
orderDetail.appointmentsviewhold = self
orderDetail.indexPathSelected = indexPath.row
navigationController?.pushViewController(orderDetail, animated: true)
}
}
}
}
thanks
Do this in customAppointmentViewCell
override func prepareForReuse() {
self. thumbnailImageView.image = UIImage()
//add here other variable and set default value for all.
}
prepareForReuse is called when a new cell will show on screen.
And Remove default value set code from your cellForRow as guided by Nikhil Manapure.
Hope this helps you.
Try this -
Implement the method prepareForReuse in your customAppointmentViewCell and in this method remove all the data and reset everything. If you are adding some subView to cell in cellForRow, remove that too.
By doing this you will be able to reduce this-
cell.clientNamePlaceHolder.text = ""
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
} else {
cell.clientNamePlaceHolder.text = ""
}
to this-
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
}
After doing this, check if the issue is still there.
Hope this helps :)
Try Passing the model object to the UICollectionViewCell class by assigning a property in cell
example:
UICollectionViewCell:
var object: Model? {
didSet{
// here do your assignment of text to various labels
}
}
CellForRow:
let cell = ...
cell.object = self.appointments[indexPath.item]
return cell
I hope this works.

Resources