Swift CollectionView is selecting multiple cell when is set to false - ios

Im currently have a horizontal collection view. I currently have multiple selection enabled set to off. For some reason when I select the first item the item toward the end of the collectionView also become selected. Thank you for the hep.
protocol customDatePickerDelegate:class {
func dateFromCustomDatePicker(date:Date)
}
class datePickerCollectionViewCell:UICollectionViewCell {
var labelNumber:UILabel = UILabel()
var minuteLabel:UILabel = {
let v = UILabel()
v.text = "Minutes"
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
minuteLabel.labelFormCustom(labelType: .dateForm)
labelNumber.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(labelNumber)
labelNumber.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
labelNumber.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
minuteLabel.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(minuteLabel)
minuteLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
minuteLabel.topAnchor.constraint(equalTo: labelNumber.bottomAnchor, constant: 0).isActive = true
self.layer.cornerRadius = 6
self.layer.borderWidth = 0.5
self.layer.borderColor = UIColor(red:205.0/255.0, green:205.0/255.0, blue:205.0/255.0, alpha: 1.0).cgColor
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class NewRquestDatePickerCollectionViewController: UIViewController,UICollectionViewDelegate {
var collectionView:UICollectionView!
override func viewDidLoad() {
setupCollectionView()
}
lazy var centerView:UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 300).isActive = true
v.backgroundColor = .white
v.addBorderCustom(.bottom)
return v
}()
lazy var durationLabel:UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.textAlignment = .center
v.font = v.font.withSize(17)
return v
}()
lazy var topActionBar:UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 60).isActive = true
v.backgroundColor = UIColor(hex: "F9F9F9")
v.addBorderCustom(.top)
v.addBorderCustom(.bottom)
return v
}()
lazy var doneButton:UIButton! = {
let v = UIButton(type:.system)
v.translatesAutoresizingMaskIntoConstraints = false
v.setTitle("Done", for: .normal)
v.addTarget(self, action: #selector(doneButtonPressed), for: .touchUpInside)
return v
}()
lazy var cancelButton:UIButton = {
let v = UIButton(type:.system)
v.translatesAutoresizingMaskIntoConstraints = false
v.setTitle("Cancel", for: .normal)
v.addTarget(self, action: #selector(dismissCurrentView), for: .touchUpInside)
return v
}()
lazy var dayLabel:UILabel = {
let v = UILabel()
// v.text = "Monday"
return v
}()
lazy var titleView:UILabel = {
let v = UILabel()
v.text = "Select a deadline"
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
var selectedIndexPath: NSIndexPath?
// var selectedTime:Int!
var timer = Timer()
var timeSeleted:TimeInterval = 10.0
let timeArray:[TimeInterval] = [10,20,30,45,60,140,400,900,1200]
var delegate:customDatePickerDelegate!
var dateSelected:Date!
func setupCollectionView(){
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
//collection view setup
self.view.addSubview(centerView)
centerView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0).isActive = true
centerView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0).isActive = true
centerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.register(datePickerCollectionViewCell.self, forCellWithReuseIdentifier: "imageCell")
collectionView.delegate = self
collectionView.dataSource = self
centerView.addSubview(topActionBar)
topActionBar.heightAnchor.constraint(equalToConstant: 49).isActive = true
topActionBar.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
topActionBar.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
topActionBar.topAnchor.constraint(equalTo: self.centerView.topAnchor, constant: 0).isActive = true
topActionBar.addSubview(cancelButton)
topActionBar.addSubview(titleView)
cancelButton.leftAnchor.constraint(equalTo: topActionBar.leftAnchor, constant: 16).isActive = true
cancelButton.centerYAnchor.constraint(equalTo: topActionBar.centerYAnchor, constant: 0).isActive = true
titleView.centerXAnchor.constraint(equalTo: topActionBar.centerXAnchor, constant: 0).isActive = true
titleView.centerYAnchor.constraint(equalTo: topActionBar.centerYAnchor, constant: 0).isActive = true
centerView.addSubview(doneButton)
centerView.addBorderCustom(.bottom)
doneButton.centerXAnchor.constraint(equalTo: centerView.centerXAnchor, constant: 0).isActive = true
doneButton.bottomAnchor.constraint(equalTo: centerView.bottomAnchor, constant: -20).isActive = true
centerView.addBorderCustom(.bottom)
centerView.addSubview(collectionView)
collectionView.heightAnchor.constraint(equalToConstant: 100).isActive = true
collectionView.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
collectionView.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
collectionView.topAnchor.constraint(equalTo: self.topActionBar.bottomAnchor, constant: 0).isActive = true
dayLabel.translatesAutoresizingMaskIntoConstraints = false
centerView.addSubview(dayLabel)
dayLabel.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor, constant: 0).isActive = true
dayLabel.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 20).isActive = true
centerView.addSubview(durationLabel)
durationLabel.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
durationLabel.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
durationLabel.topAnchor.constraint(equalTo: self.collectionView.bottomAnchor, constant: 0).isActive = true
durationLabel.bottomAnchor.constraint(equalTo: self.doneButton.topAnchor, constant: 20).isActive = true
timerStart()
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.contentInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
collectionView.isPagingEnabled = true
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor(hex:"EFF3F4")
centerView.addBorderCustom(.bottom)
collectionView.allowsMultipleSelection = false
}
}
extension NewRquestDatePickerCollectionViewController {
func dismissCurrentView(){
self.dismiss(animated: true , completion: nil)
}
func doneButtonPressed(){
delegate.dateFromCustomDatePicker(date: dateSelected)
dismissCurrentView()
}
func tappedDeadlineSelection(){
}
func timerStart(){
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
let date = Date()
let adjustedDate = date.addingTimeInterval(self.timeSeleted * 60.0)
self.dateSelected = adjustedDate
self.durationLabel.text = String(describing: adjustedDate.string(withFormat: "MM/dd/yy, h:mm a"))
self.dayLabel.text = String(describing: adjustedDate.string(withFormat: "EEEE"))
})
} else {
// Fallback on earlier versions
}
}
}
extension NewRquestDatePickerCollectionViewController:UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return timeArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! datePickerCollectionViewCell
cell.awakeFromNib()
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cellInfo = cell as! datePickerCollectionViewCell
//converTime
cellInfo.labelNumber.text = String(self.timeArray[indexPath.row])
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
let timeAdded = self.timeArray[indexPath.row]
cell.backgroundColor = UIColor(hex: "F2784B")
// let timeAdded = self.timeArray[indexPath.row]
cell.labelNumber.textColor = .white
cell.minuteLabel.textColor = .white
cell.layer.borderColor = UIColor.white.cgColor
timeSeleted = timeAdded
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
cell.backgroundColor = .white
cell.labelNumber.textColor = .black
cell.minuteLabel.textColor = UIColor().RquestCustomColors(.fontGray)
// collectionView.performBatchUpdates(nil, completion: nil)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 64, height: 64)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 30.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 30.0
}
}

Because you are reusing existed cell, you should keep track selected item index and update cell state as below:
var selectedIndex: IndexPath?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
let timeAdded = self.timeArray[indexPath.row]
cell.backgroundColor = UIColor(hex: "F2784B")
// let timeAdded = self.timeArray[indexPath.row]
cell.labelNumber.textColor = .white
cell.minuteLabel.textColor = .white
cell.layer.borderColor = UIColor.white.cgColor
timeSeleted = timeAdded
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
// add the following codes
let lastSelectedIndex = self.selectedIndex
self.selectedIndex = indexPath
// unselect last selected index
collectionView.reloadItems(at: [lastSelectedIndex!])
// reload new selected index
collectionView.reloadItems(at: [self.selectedIndex!])
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cellInfo = cell as! datePickerCollectionViewCell
//converTime
cellInfo.labelNumber.text = String(self.timeArray[indexPath.row])
// add this line of code
cell.isSelected = (self.selectedIndex == indexPath)
}

You should make use of the "isSelected" method for the collection view cell. This way you will not have not save any selected indexpath.
So I recommend using this method:
Firstly,
collectionView.allowsMultipleSelection = false
on the UICollectionViewCell you can override the isSelected method
didSet {
if isSelected {
// Change UI for selected state
radioButton.setImage(#imageLiteral(resourceName: "greenTick"), for: .normal)
} else {
// Chage UI for unselected state
radioButton.setImage(#imageLiteral(resourceName: "radioInactive"), for: .normal)
}
}
Finally when you need to find out the indexpath for the selected item.
guard let selectedIndex = self.collectionView.indexPathsForSelectedItems?.first else { return }

Related

Collection view selected cell background view color not changing in IOS 15

When the collection view cell is selected, cell background view and the other labels in that cell should change color. The below code is working for below ios 15. If i change didSet to willSet in the below code, it is working for ios 15 but its not working below ios 15. Is there a solution to change the color for the selected custom cell? I am adding the collection view delegate and datasource methods code as well.
override var isSelected: Bool{
didSet{
if self.isSelected
{
super.isSelected = true
lblName.textColor = .white
cellBGView.backgroundColor = .themeColor
cellInfoBtn.tintColor = .white
}
else
{
super.isSelected = false
lblName.textColor = .themeColor
cellBGView.backgroundColor = .white
cellInfoBtn.tintColor = .themeColor
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
selectIndex = indexPath.row
let cell = collectionView.cellForItem(at: indexPath) as! CustomCollectionCell
selectedIndexPath = indexPath
selectIndexSec = indexPath.section
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionCell", for: indexPath) as! CustomCollectionCell cell.cellInfoBtn.tag = indexPath.row
cell.cellInfoBtn.addTarget(self, action: #selector(infoBtnTapped(_:)), for: .touchUpInside)
if selectIndex == indexPath.row { cell.isSelected=true }
else { cell.isSelected=false }
return cell
}
I tried the above code and i need to find a common solution for old version as well as version above 15. If there is already an answer exists, please redirect me to it.
You are doing a lot of extra work.
A UICollectionView tracks its own selections with .indexPathsForSelectedItems, so there is no need for the additional tracking with your selectedIndexPath and selectIndexSec.
Also, if you're overriding isSelected, there's no need to call .reloadData().
Here's a complete example -- I added the lblName and cellBGView but not the button:
class AutoHighlightCell: UICollectionViewCell {
let lblName = UILabel()
let cellBGView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
lblName.textAlignment = .center
[cellBGView, lblName].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
cellBGView.addSubview(lblName)
contentView.addSubview(cellBGView)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
cellBGView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
cellBGView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
cellBGView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
cellBGView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
lblName.topAnchor.constraint(equalTo: cellBGView.topAnchor, constant: 16.0),
lblName.leadingAnchor.constraint(equalTo: cellBGView.leadingAnchor, constant: 24.0),
lblName.trailingAnchor.constraint(equalTo: cellBGView.trailingAnchor, constant: -24.0),
lblName.bottomAnchor.constraint(equalTo: cellBGView.bottomAnchor, constant: -16.0),
])
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.black.cgColor
// set default non-selected properties
lblName.textColor = .blue
cellBGView.backgroundColor = .yellow
}
override var isSelected: Bool {
didSet {
lblName.textColor = isSelected ? .white : .blue
cellBGView.backgroundColor = isSelected ? .systemGreen : .yellow
}
}
}
class AutoHighlightCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
let instructionLabel: UILabel = {
let v = UILabel()
v.textAlignment = .center
v.text = "Tap Here"
v.numberOfLines = 0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
let fl = UICollectionViewFlowLayout()
fl.estimatedItemSize = CGSize(width: 80, height: 50)
fl.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: fl)
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
instructionLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(instructionLabel)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 80.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
collectionView.heightAnchor.constraint(equalToConstant: 80.0),
instructionLabel.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 60.0),
instructionLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
instructionLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
collectionView.register(AutoHighlightCell.self, forCellWithReuseIdentifier: "cell")
collectionView.dataSource = self
collectionView.delegate = self
// so we can see the collectionView frame
collectionView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
instructionLabel.addGestureRecognizer(t)
instructionLabel.isUserInteractionEnabled = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let c = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! AutoHighlightCell
c.lblName.text = "\(indexPath)"
return c
}
#objc func gotTap(_ g: UITapGestureRecognizer) {
var s = "Tap Here\n\n"
if let pth = collectionView.indexPathsForSelectedItems?.first {
s += "Selected Path: \(pth)"
} else {
s += "No Item Selected"
}
instructionLabel.text = s
}
}
When run, it will look like this:
If you tap "Tap Here" before selecting a cell, you'll see:
after selecting a cell:
Notice that when you scroll the cells in and out of view, the "Selected" state is maintained by the collection view, and the cell's UI is updated in override var isSelected ... no need to worry about any of that in cellForItemAt or in didSelectItemAt

UITableView is duplicating/repeating number of rows in section

I am currently developing a Fitness Application and working on Workout View. It has a functionality similar to to-do checklist. So basically the user is marking Sets of a certain exercise that he finished. I know that it is needed to prepare TableViewCells for reuse, and I did that for the state when all the sets of exercise is done and user shouldn't be able to interact whit that TableViewCell anymore. The only thing that keeps getting duplicated is numberOfRowsInSection. Guys please help me find the missing part, I have been trying for two days at this point:(
TableView is inside the collectionViewCell so I am initializing it from there. I am using custom delegate as I have to have an access to tableView from the view that holds collectionView.
protocol TableViewCellDelegate: AnyObject {
func tableView(tableViewCell: WorkoutStartedTVCurrentExerciseCell, index: Int, didTappedInTableViewCell: WorkoutStartedCell)
// other delegate methods that you can define to perform action in viewcontroller
}
class WorkoutStartedCell: UICollectionViewCell {
weak var cellDelegateTV: TableViewCellDelegate?
let scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = UIColor.clear
view.isScrollEnabled = true
view.contentMode = .center
view.showsHorizontalScrollIndicator = false
view.isMultipleTouchEnabled = true
view.isUserInteractionEnabled = true
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.clear
label.textColor = UIColor.black
label.textAlignment = .center
label.text = "Incline Bench Press"
label.font = UIFont.systemFont(ofSize: 23.0, weight: .semibold)
return label
}()
let numberOfExercisesLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.clear
label.textColor = UIColor.black.withAlphaComponent(0.7)
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16.5, weight: .medium)
return label
}()
let container: UIView = {
let view = UIView()
view.layer.cornerRadius = 10
view.backgroundColor = UIColor.black
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.clipsToBounds = false
view.layer.shadowOpacity = 0.35
view.layer.shadowRadius = 10
view.layer.shadowColor = UIColor.black.cgColor
return view
}()
let tableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = UIColor.clear
tableView.separatorStyle = .none
tableView.register(WorkoutStartedTVCurrentExerciseCell.self, forCellReuseIdentifier: "currentExerciseCellID")
tableView.layer.cornerRadius = 0
tableView.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.showsHorizontalScrollIndicator = false
tableView.showsVerticalScrollIndicator = true
tableView.isScrollEnabled = true
return tableView
}()
var number_of_sets : Int!
var number_of_reps : Int!
var completed_sets = [Int]()
var remaining_sets = [Int]()
//var current_set: IndexPath!
//var completedSets: [Int]!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
contentView.isUserInteractionEnabled = true
isMultipleTouchEnabled = true
//tableView.estimatedRowHeight = 0
//tableView.estimatedSectionHeaderHeight = 0
//tableView.estimatedSectionFooterHeight = 0
//tableView.delegate = self
//tableView.dataSource = self
tableView.isScrollEnabled = false
contentView.addSubview(scrollView)
scrollView.addSubview(titleLabel)
scrollView.addSubview(numberOfExercisesLabel)
scrollView.addSubview(container)
scrollView.addSubview(tableView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: heightAnchor).priority = UILayoutPriority.defaultLow
//scrollView.delegate = self
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
titleLabel.sizeToFit()
numberOfExercisesLabel.translatesAutoresizingMaskIntoConstraints = false
numberOfExercisesLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10).isActive = true
numberOfExercisesLabel.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
numberOfExercisesLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
numberOfExercisesLabel.sizeToFit()
container.translatesAutoresizingMaskIntoConstraints = false
container.topAnchor.constraint(equalTo: numberOfExercisesLabel.bottomAnchor, constant: 15).isActive = true
container.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
container.widthAnchor.constraint(equalToConstant: self.frame.width - 0).isActive = true
container.heightAnchor.constraint(equalToConstant: self.frame.width - 0).isActive = true
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: container.bottomAnchor, constant: 20).isActive = true
tableView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
override func prepareForReuse() {
super.prepareForReuse()
number_of_sets = nil
number_of_reps = nil
remaining_sets.removeAll()
completed_sets.removeAll()
tableView.delegate = nil
tableView.dataSource = nil
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension WorkoutStartedCell: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return remaining_sets.count + completed_sets.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "currentExerciseCellID", for: indexPath) as! WorkoutStartedTVCurrentExerciseCell
cell.selectionStyle = .none
cell.Set.text = "\(Array(1...number_of_sets)[indexPath.row])"
cell.Reps.text = "\(number_of_reps ?? 1)"
if completed_sets.count == number_of_sets {
cell.isUserInteractionEnabled = false
} else {
cell.isUserInteractionEnabled = true
}
if completed_sets.contains(where: {$0 == indexPath.row}) == false, indexPath.row == remaining_sets.first {
//Current Set
cell.Set.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.white
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
} else if completed_sets.contains(indexPath.row) == true, remaining_sets.contains(indexPath.row) == false {
//Completed Set
cell.Set.textColor = UIColor.black.withAlphaComponent(0.7)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = UIColor.black.withAlphaComponent(0.7)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = UIColor.black.withAlphaComponent(0.7)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.darkGray.withAlphaComponent(0.9)
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
} else if completed_sets.contains(indexPath.row) == false, remaining_sets.contains(indexPath.row) == true, indexPath.row != remaining_sets.first {
//Remaining Sets
cell.Set.textColor = UIColor.black.withAlphaComponent(1.0)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = UIColor.black.withAlphaComponent(1.0)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = UIColor.black.withAlphaComponent(1.0)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.white
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? WorkoutStartedTVCurrentExerciseCell
self.cellDelegateTV?.tableView(tableViewCell: cell!, index: indexPath.row, didTappedInTableViewCell: self)
}
}
Here is how I pass the data from ViewController and setting CollectionView delegate and data source.
extension workoutStartedView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return exercise_names.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let exercisesCount = Array(1...exercise_names.count)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! WorkoutStartedCell
cell.number_of_reps = Int(number_of_reps[indexPath.item])!
cell.number_of_sets = Int(number_of_sets[indexPath.item])!
cell.remaining_sets = remainingSets[indexPath.item]
cell.completed_sets = completedSets[indexPath.item]
cell.titleLabel.text = exercise_names[indexPath.item]
cell.numberOfExercisesLabel.text = "Exercise \(exercisesCount[indexPath.item]) of \(exercise_names.count)"
cell.cellDelegateTV = self
cell.tableView.heightAnchor.constraint(equalToConstant: 75 * CGFloat(Int(self.number_of_sets[indexPath.item])!)).isActive = true
cell.scrollView.contentSize = CGSize(width: collectionView.frame.width, height: 100 + (collectionView.frame.width) + (75 * CGFloat(Int(self.number_of_sets[indexPath.item])!)))
cell.scrollView.scrollToTop(animated: false)
cell.tableView.delegate = cell.self
cell.tableView.dataSource = cell.self
cell.tableView.reloadData()
//cell.layoutIfNeeded()
cell.tag = Array(0...exercise_names.count - 1)[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width - 40, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Here I am handling data from collectionViewCell throw custom delegate
extension workoutStartedView: TableViewCellDelegate {
func tableView(tableViewCell: WorkoutStartedTVCurrentExerciseCell, index: Int, didTappedInTableViewCell: WorkoutStartedCell) {
//if didTappedInTableViewCell.remaining_sets.count > 1 {
didTappedInTableViewCell.completed_sets.append(didTappedInTableViewCell.remaining_sets.first!)
didTappedInTableViewCell.remaining_sets.removeFirst()
if completedSets.count > 0 {
if self.completedSets.count > didTappedInTableViewCell.tag {
self.completedSets[didTappedInTableViewCell.tag] = didTappedInTableViewCell.completed_sets
} else if self.completedSets.count <= didTappedInTableViewCell.tag {
self.completedSets.append(didTappedInTableViewCell.completed_sets)
}
} else if completedSets.count <= 0 {
self.completedSets.append(didTappedInTableViewCell.completed_sets)
}
if self.remainingSets[didTappedInTableViewCell.tag].count > 0 {
self.remainingSets[didTappedInTableViewCell.tag] = didTappedInTableViewCell.remaining_sets
} else if self.remainingSets[didTappedInTableViewCell.tag].count <= 1 {
self.remainingSets.removeFirst()
}
print(didTappedInTableViewCell.completed_sets)
print(didTappedInTableViewCell.remaining_sets)
print(self.completedSets)
print(self.remainingSets)
//collectionView.reloadData()
didTappedInTableViewCell.tableView.reloadData()
}
}
Hey Guys I finally found the solution!:D
The problem was that I wasn't resetting all the cell properties in cellForRowAt function
By adding this lines my problem was solved
cell.titleLabel.text = ""
cell.numberOfExercisesLabel.text = ""
cell.tableView.removeAllConstraints()
cell.scrollView.contentSize = CGSize.zero
I just didn't think that the constraints and scrollView's contentSize should also be reseted:D

UICollectionView weird cells animation when dismiss mode of the keyboard is interactive

I'm trying to achieve a chat system using UICollectionView -The collectionview is turned upside down and so are the cells using CGAffineTransform(scaleX: -1, y: 1)- and so far everything is going well, I'm calculating cell sizes manually using NSString.boundingRect and it's working as expected, then I enabled the collectionview's interactive keyboard dismissal since then whenever I drag the keyboard a little bit then I let go it results into a really weird animation which I can't seem to figure out what's triggering it.
I also use Typist which is a small utility class that facilitates keyboard handling https://github.com/totocaster/Typist, I'm not really suspecting it since it is a simple wrapper UIKeyboard notifications.
I've tried several stuff including but not limited to
1-Disabling animations when showing cell using
UIView.setAnimationsEnabled(false) then enabling it again just before returning the cell which did not work.
2-Removing the upside-down approach altogether, and again nope even when it's in a normal transform the bug still occurs
3-Rewrote the entire UICollectionView implementation to UITableView implementation which -surprisingly- yielded a better result the weird animation isn't as strong as it's on the UICollectionView but it's still happening to some extent
4-Removing Typist altogether and reverting back to NotificationCenter and manual handling and nope, does not work.
UICollectionView initialization
lazy var chatCollectionView: UICollectionView = {
let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.scrollDirection = .vertical
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .white
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.register(OutgoingTextCell.self, forCellWithReuseIdentifier: OutgoingTextCell.className)
collectionView.register(IncomingTextCell.self, forCellWithReuseIdentifier: IncomingTextCell.className)
collectionView.register(OutgoingImageCell.self, forCellWithReuseIdentifier: OutgoingImageCell.className)
collectionView.register(IncomingImageCell.self, forCellWithReuseIdentifier: IncomingImageCell.className)
collectionView.transform = CGAffineTransform(scaleX: 1, y: -1)
collectionView.semanticContentAttribute = .forceLeftToRight
collectionView.keyboardDismissMode = .interactive
return collectionView
}()
UICollectionView DataSource / Delete implementation
extension ChatViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return presenter.numberOfRows
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if presenter.isSender(at: indexPath) {
switch presenter.messageType(at: indexPath) {
case .text:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OutgoingTextCell.className, for: indexPath) as! OutgoingTextCell
presenter.configure(cell: AnyConfigurableCell(cell), at: indexPath)
return cell
case .photo:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OutgoingImageCell.className, for: indexPath) as! OutgoingImageCell
presenter.configure(cell: AnyConfigurableCell(cell), at: indexPath)
return cell
}
} else {
switch presenter.messageType(at: indexPath) {
case .text:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: IncomingTextCell.className, for: indexPath) as! IncomingTextCell
presenter.configure(cell: AnyConfigurableCell(cell), at: indexPath)
return cell
case .photo:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: IncomingImageCell.className, for: indexPath) as! IncomingImageCell
presenter.configure(cell: AnyConfigurableCell(cell), at: indexPath)
return cell
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if presenter.messageType(at: indexPath) == .photo {
return CGSize(width: view.frame.width, height: 250)
} else {
if let height = cachedSizes[presenter.uuidForMessage(at: indexPath)] {
return CGSize(width: view.frame.width, height: height)
} else {
let height = calculateTextHeight(at: indexPath)
cachedSizes[presenter.uuidForMessage(at: indexPath)] = height
return CGSize(width: view.frame.width, height: height)
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == presenter.numberOfRows - 1 && !isPaginating {
presenter.loadNextPage()
}
}
private func calculateTextHeight(at indexPath: IndexPath) -> CGFloat {
let approximateSize = CGSize(width: view.frame.width - 88, height: .greatestFiniteMagnitude)
let estimatedHeight = NSString(string: presenter.contentForMessage(at: indexPath)).boundingRect(with: approximateSize, options: .usesLineFragmentOrigin, attributes: [.font: DinNextFont.regular.getFont(ofSize: 14)], context: nil).height
return estimatedHeight + 40
}
}
Cell implementation
class OutgoingTextCell: UICollectionViewCell, ConfigurableCell {
lazy var containerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .coral
view.layer.cornerRadius = 10
return view
}()
lazy var contentLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.numberOfLines = 0
label.font = DinNextFont.regular.getFont(ofSize: 14)
return label
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [timeLabel, checkMarkImageView])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.distribution = .equalSpacing
stackView.alignment = .center
stackView.spacing = 4
return stackView
}()
private lazy var checkMarkImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "ic_check")?.withRenderingMode(.alwaysTemplate))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.tintColor = .white
imageView.heightAnchor.constraint(equalToConstant: 8).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 10).isActive = true
return imageView
}()
lazy var timeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.font = DinNextFont.regular.getFont(ofSize: 10)
label.text = "12:14"
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func addSubviews() {
addSubview(containerView)
containerView.addSubview(contentLabel)
containerView.addSubview(stackView)
}
func setupContainerViewConstraints() {
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: topAnchor, constant: 0),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8),
containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 100),
containerView.heightAnchor.constraint(greaterThanOrEqualToConstant: 34),
containerView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: 64)
])
}
private func setupContentLabelConstraints() {
NSLayoutConstraint.activate([
contentLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 4),
contentLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8),
contentLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8),
])
}
private func setupStackViewConstraints() {
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: contentLabel.bottomAnchor, constant: 0),
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -6),
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -4),
stackView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor, constant: 6),
stackView.heightAnchor.constraint(equalToConstant: 20),
])
}
private func layoutUI() {
addSubviews()
setupContainerViewConstraints()
setupContentLabelConstraints()
setupStackViewConstraints()
}
func configure(model: MessageViewModel) {
containerView.transform = CGAffineTransform(scaleX: 1, y: -1)
contentLabel.text = model.content
timeLabel.text = model.time
checkMarkImageView.isHidden = !model.isSent
}
}
The output of UICollectionView is as the following
https://www.youtube.com/watch?v=RajfZk5lGCQ
The output of the UITableview is as the following
https://www.youtube.com/watch?v=6ayG7WhYKXo
It might not be really clear but if you look closely you can see the cells are "briefly" animating and with longer messages it looks kind of "sliding animation" which does not leak appealing at all.

removing subview (uiview) in viewcontroller from collectionview

How do I remove a uiview that is added into a viewcontroller whenever the user clicks on one of the collectionview? My collectionview is located inside of its own viewcontroller when the user clicks one of the collectionviewcell it will dismiss the controller (it's working) and then it will remove the contextTxt within the mainviewcontroller It did dismiss the view but it failed to remove the contextTxt and replacing it with a new view. In other words, the collectionviewcell did not trigger the #objc func inside the mainviewcontroller. Why won't it trigger?? and how do resolve this problem? Here is the code
class mainViewController: UIViewController {
let navbar:navbarView = {
let content = navbarView()
return content
}()
let contentTxt:UITextView = {
let content = UITextView()
content.backgroundColor = UIColor.green
return content
}()
let bottomBtn:UIButton = {
let content = UIButton()
content.backgroundColor = UIColor.red
return content
}()
override func viewDidLoad() {
super.viewDidLoad()
navbar.translatesAutoresizingMaskIntoConstraints = false
contentTxt.translatesAutoresizingMaskIntoConstraints = false
bottomBtn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navbar)
view.addSubview(contentTxt)
contentTxt.addSubview(bottomBtn)
navbar.topAnchor.constraint(
equalTo: view.topAnchor, constant: 20).isActive = true
navbar.centerXAnchor.constraint(
equalTo: view.centerXAnchor).isActive = true
navbar.widthAnchor.constraint(
equalTo: view.widthAnchor).isActive = true
navbar.heightAnchor.constraint(
equalToConstant: 50).isActive = true
contentTxt.topAnchor.constraint(
equalTo: navbar.bottomAnchor, constant: 5).isActive = true
contentTxt.centerXAnchor.constraint(
equalTo: view.centerXAnchor).isActive = true
contentTxt.widthAnchor.constraint(
equalTo: view.widthAnchor).isActive = true
contentTxt.bottomAnchor.constraint(
equalTo: view.bottomAnchor, constant: 0).isActive = true
bottomBtn.bottomAnchor.constraint(
equalTo: contentTxt.bottomAnchor).isActive = true
bottomBtn.centerXAnchor.constraint(
equalTo: contentTxt.centerXAnchor).isActive = true
bottomBtn.widthAnchor.constraint(
equalToConstant: 40).isActive = true
bottomBtn.heightAnchor.constraint(
equalToConstant: 40).isActive = true
}
#objc func addConnections(){
self.contentTxt.removeFromSuperview()
let connect:connectView = {
let content = connectView()
content.backgroundColor = UIColor.red
return content
}()
connect.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(connect)
connect.topAnchor.constraint(
equalTo: navbar.bottomAnchor, constant: 5).isActive = true
connect.centerXAnchor.constraint(
equalTo: view.centerXAnchor).isActive = true
connect.widthAnchor.constraint(
equalTo: view.widthAnchor).isActive = true
connect.bottomAnchor.constraint(
equalTo: view.bottomAnchor, constant: 0).isActive = true
}
#objc func sideController(){
let next = self.storyboard?.instantiateViewController(
withIdentifier: "sideViewController") as! sideViewController
self.present(next, animated: true, completion: nil)
}
#objc func profileController(){
let next = self.storyboard?.instantiateViewController(
withIdentifier: "profileViewController") as! profileViewController
self.present(next, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the collectionview code:
class sideCollectionView:UIView, UICollectionViewDelegateFlowLayout,UICollectionViewDataSource {
var currentVc:sideViewController?
var mainVc=mainViewController()
let arrayLbl = ["connection","achievement","template","setting"]
let arrayImg = ["connection","achievement","template","setting"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrayLbl.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! sideCollectionViewCell
cell.titleImg.image = UIImage(named: "\(arrayImg[indexPath.row])")
cell.titleLbl.text = arrayLbl[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (self.frame.width / 2) - 40, height: (self.frame.width / 2) - 40)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(25, 25, 10, 25)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0{
print("connection")
currentVc?.bye()
mainVc.addConnections()
}
if indexPath.row == 1{
print("achievement")
currentVc?.bye()
}
if indexPath.row == 2{
print("template")
currentVc?.bye()
}
if indexPath.row == 3{
print("setting")
currentVc?.bye()
}
}
lazy var collectionViews: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.clear
cv.dataSource = self
cv.delegate = self
return cv
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func setupViews(){
collectionViews.register(sideCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionViews.translatesAutoresizingMaskIntoConstraints = false
backgroundColor = UIColor.clear
addSubview(collectionViews)
collectionViews.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
collectionViews.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0).isActive = true
collectionViews.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true
collectionViews.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
collectionViews.widthAnchor.constraint(equalTo: widthAnchor, constant: 0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Because var mainVc=mainViewController() creates a new mainViewController which is not the existing mainViewController.
You can try getting the parent mainViewController by this way.
var mainVc: mainViewController? {
return currentVc?.presentingViewController as? mainViewController
}
When presenting sideViewController, set the mainVc variable to self so that it is pointing to the actual mainVc object:
#objc func sideController(){
let next = self.storyboard?.instantiateViewController(withIdentifier: "sideViewController") as! sideViewController
next.mainVc = self
self.present(next, animated: true, completion: nil)
}

How to define dynamic heights for UICollectionViewCells with a TextView inside

This is a popular question but I'm still not able to find a simple answer of how to define a dynamic height for a UICollectionViewCell with a TextView inside. I found this answer UICollectionView - dynamic cell height? but I'm not using interface and I would like a solution for interfaces built in code.
import UIKit
class ResumeController : UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
//layout.estimatedItemSize = CGSize(width: 100, height: 100)
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.dataSource = self
cv.delegate = self
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(FirmCell.self, forCellWithReuseIdentifier: self.cellId)
return cv
}()
override func viewDidLoad() {
view.backgroundColor = .white
setupViews()
}
func setupViews() {
setupCollectionView()
}
func setupCollectionView() {
view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100.0)
}
}
class FirmCell : UICollectionViewCell {
let imageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .orange
// iv.image = somelogo
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
lazy var textView: UITextView = {
let tv = UITextView()
tv.isEditable = false
tv.isSelectable = false
tv.isScrollEnabled = false
tv.attributedText = self.attributedText()
tv.translatesAutoresizingMaskIntoConstraints = false
tv.layer.borderWidth = 0.5
tv.layer.borderColor = UIColor.blue.cgColor
return tv
}()
let separatorLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.9, alpha: 1)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
func attributedText() -> NSAttributedString {
let text = NSMutableAttributedString()
// company
var companyAttr = [String: Any]()
companyAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 15, weight: UIFontWeightBold)
companyAttr[NSForegroundColorAttributeName] = UIColor.black
text.append(NSAttributedString(string: "line1" , attributes: companyAttr))
// period
var periodAttr = [String: Any]()
periodAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 14)
periodAttr[NSForegroundColorAttributeName] = UIColor.lightGray
text.append(NSAttributedString(string: " line1" , attributes: periodAttr))
// body
var bodyAttr = [String: Any]()
bodyAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 14, weight: UIFontWeightThin)
bodyAttr[NSForegroundColorAttributeName] = UIColor.black
text.append(NSAttributedString(string: "\na huge amount of text goes here ... trying to figure out a way to have different collectionview cells row height", attributes: bodyAttr))
return text
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
setupImageView()
}
func setupImageView() {
addSubview(imageView)
imageView.topAnchor.constraint(equalTo: topAnchor, constant: 9.0).isActive = true
imageView.leftAnchor.constraint(equalTo: leftAnchor, constant: 9.0).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 40.0).isActive = true
setupTextView()
}
func setupTextView() {
addSubview(textView)
textView.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 0).isActive = true
textView.leftAnchor.constraint(equalTo: imageView.rightAnchor, constant: 7.0).isActive = true
textView.rightAnchor.constraint(equalTo: rightAnchor, constant: -9.0).isActive = true
textView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
Could someone provide some pointers?

Resources