removing subview (uiview) in viewcontroller from collectionview - ios

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)
}

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

How to connect UIPageControl and CollectionView?

I have collection view with Custom View Cell. There are scroll view and three image view in a custom view cell.
My ViewController has UIPageControll, but I don't know how to connect UIPageControll and scroll view.
My code
ViewController:
class MainScrenenViewController: UIViewController {
let data = [
CustomData(title: "A", backgroundImage: #imageLiteral(resourceName: "Onboard")),
CustomData(title: "B", backgroundImage: #imageLiteral(resourceName: "Onboard")),
CustomData(title: "B", backgroundImage: #imageLiteral(resourceName: "Onboard")),
]
//UIPage Controller
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.numberOfPages = data.count
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .touchUpInside)
return pageControl
}()
var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(DayWeatherCell.self, forCellWithReuseIdentifier: "sliderCell")
collectionView.layer.cornerRadius = 5
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor(red: 0.125, green: 0.306, blue: 0.78, alpha: 1)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .brown
view.addSubview(collectionView)
view.addSubview(pageControl)
collectionView.dataSource = self
collectionView.delegate = self
setupConstraints()
}
//MARK: ~FUNCTIONS
func setupConstraints() {
let constraints = [
collectionView.widthAnchor.constraint(equalToConstant: 344),
collectionView.heightAnchor.constraint(equalToConstant: 212),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 112),
pageControl.topAnchor.constraint(equalTo: cityLabel.bottomAnchor, constant: 10),
pageControl.widthAnchor.constraint(equalToConstant: 100),
pageControl.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
]
NSLayoutConstraint.activate(constraints)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//Selector for UIPage Controller
#objc func pageControlTapHandler(sender: UIPageControl) {
//I don't know what I need to do here
}
extension MainScrenenViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "sliderCell", for: indexPath) as! DayWeatherCell
cell.backgroundColor = .red
return cell
}
}
extension MainScrenenViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("User tapped on item \(indexPath.row)")
}
}
extension MainScrenenViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
}
}
extension MainScrenenViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
}
My CollectionViewCell:
class DayWeatherCell: UICollectionViewCell, UIScrollViewDelegate {
weak var mainScreenViewController: MainScrenenViewController?
var data: CustomData? {
didSet {
guard let data = data else { return }
imageView.image = data.backgroundImage
}
}
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "Onboard")
imageView.layer.cornerRadius = 5
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.delegate = self
return scrollView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(scrollView)
contentView.addSubview(imageView)
self.contentView.layer.cornerRadius = 10
let constraints = [
scrollView.topAnchor.constraint(equalTo: contentView.topAnchor),
scrollView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
scrollView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
scrollView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
required init?( coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
enter image description here
You can use this. In this code block, collection view cell size equal to collection view and collection view scroll horizontally. I hope, this helps you.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageControl.currentPage = Int(offSet + horizontalCenter) / Int(width)
}

Use of unresolved identifier 'view'

Trying to add constraints to a collection view.
Keep getting the error, "Use of unresolved identifier 'view'"
Any help is much appreciated.
import UIKit
class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
// cv.backgroundColor = UIColor.white
cv.dataSource = self
cv.delegate = self
return cv
}()
let cellId = "cellId"
override init(frame:CGRect) {
super.init(frame: frame)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
addSubview(self.collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.leadingAnchor.constraint(
equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(
equalTo: view.trailingAnchor).isActive = true
collectionView.topAnchor.constraint(
equalTo: view.topAnchor,
constant: -20).isActive = true
collectionView.heightAnchor.constraint(
equalTo: view.heightAnchor,
multiplier: 0.10).isActive = true
backgroundColor = UIColor.red
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = .blue
return cell
}
There is no view property in a UIView, it's a property of UIViewController.
Since self is the view in this case, replace:
equalTo: view.leadingAnchor).isActive = true
with:
equalTo: self.leadingAnchor).isActive = true
and same for other ones.
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: self.topAnchor,constant: -20),
collectionView.heightAnchor.constraint(equalTo: self.heightAnchor,multiplier: 0.10)
)]
You need to replace view with self because this is not viewcontroller this is MenuView so yo need to use self for that:
collectionView.leadingAnchor.constraint(
equalTo: self.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(
equalTo: self.trailingAnchor).isActive = true
collectionView.topAnchor.constraint(
equalTo: self.topAnchor,
constant: -20).isActive = true
collectionView.heightAnchor.constraint(
equalTo: self.heightAnchor,
multiplier: 0.10).isActive = true

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?

Swift CollectionView is selecting multiple cell when is set to false

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 }

Resources