UITableView scroll freezes when scrolling fast - ios

I am using custom tableview cells in a tableview. The data is loaded from the server and height calculation of that particular cell is done inside the cell only.
<iframe width="560" height="315" src="https://www.youtube.com/embed/h-FjYkSBuNM" frameborder="0" allowfullscreen></iframe>
I am attaching the code for tableview cell for row at indexpath, custom cell method and code for get request.
class QuesAnsFeedTableViewCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.questionLabel.preferredMaxLayoutWidth = questionLabel.frame.width
self.answerLabel.preferredMaxLayoutWidth = answerLabel.frame.width
super.layoutSubviews()
}
func setup(){
topLeftLabel = UILabel()
topLeftLabel.font = UIFont(name: regularFont, size: 12)
topLeftLabel.text = "Yesterday"
topLeftLabel.textColor = CommonFunctions.hexStringToUIColor(hex: lightGray)
topRightLabel = UILabel()
topRightLabel.font = UIFont(name: regularFont, size: 12)
topRightLabel.textColor = CommonFunctions.hexStringToUIColor(hex: lightGray)
topRightLabel.text = ""
topRightLabel.textAlignment = .right
questionLabel = UILabel()
questionLabel.font = UIFont(name: mediumFont, size: 14)
questionLabel.text = "First Ques Comes Here and ans will be below this question"
questionLabel.numberOfLines = 0
questionLabel.lineBreakMode = .byWordWrapping
userImageView = UIImageView()
userImageView.backgroundColor = .purple
userImageView.layer.cornerRadius = CGFloat(sidePadding)/2
userImageView.clipsToBounds = true
userNameLabel = UILabel()
userNameLabel.font = UIFont(name: regularFont, size: 12)
userNameLabel.text = ""
answerLabel = UILabel()
answerLabel.font = UIFont(name: regularFont, size: 14)
answerLabel.text = ""
answerLabel.numberOfLines = 0
answerLabel.lineBreakMode = .byWordWrapping
viewOtherAnswerLabel = UILabel()
viewOtherAnswerLabel.font = UIFont(name: mediumFont, size: 12)
viewOtherAnswerLabel.text = ""
viewOtherAnswerLabel.textAlignment = .center
viewOtherAnswerLabel.textColor = CommonFunctions.hexStringToUIColor(hex: lightGray)
writeAnswerLabel = UILabel()
writeAnswerLabel.font = UIFont(name: mediumFont, size: 14)
writeAnswerLabel.backgroundColor = CommonFunctions.hexStringToUIColor(hex: crispBlue)
writeAnswerLabel.text = "Write Answer"
writeAnswerLabel.textAlignment = .center
writeAnswerLabel.textColor = .white
tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tappedCell(sender:)))
tapGesture.numberOfTapsRequired = 1
self.addGestureRecognizer(tapGesture)
// self.addSubview(likeButton)
// self.addSubview(descriptionLabel)
}
func updateData(data:NSDictionary) -> CGFloat{
if let viewCount = data["vc"] {
topRightLabel.text = "\(viewCount) read"
}
if let ques = data["q"] as? String{
topLeftLabel.frame = CGRect(x:sidePadding/2, y: 2*sidePaddingForCollectionCells, width: screenWidth/2-sidePadding, height: Int(CommonFunctions.calculateHeight(inString: topLeftLabel.text!, forFont: topLeftLabel.font, andWidthOfLabel: CGFloat(screenWidth/2))))
topRightLabel.frame = CGRect(x: screenWidth/2, y: 2*sidePaddingForCollectionCells, width: screenWidth/2-sidePadding/2, height: Int(topLeftLabel.frame.height))
let newHeight = CommonFunctions.calculateHeight(inString: ques,forFont:questionLabel.font,andWidthOfLabel:questionLabel.frame.width)
questionLabel.frame = CGRect(x:sidePadding/2 ,y: Int(topLeftLabel.frame.maxY)+sidePaddingForCollectionCells,width: screenWidth - sidePadding, height: Int(ceil(Float(newHeight))))
questionLabel.text = ques
self.addSubview(topLeftLabel)
self.addSubview(topRightLabel)
self.addSubview(questionLabel)
// questionLabel.attributedText = CommonFunctions.justifiedText(string: ques)
}
if let user = data.object(forKey: "user") as? NSDictionary{
if let usrName = user.value(forKey: "name"){
userNameLabel.text = "\(usrName)"
}
if let imgLink = user["image"] as? String{
if let url = URL(string: imgLink){
userImageView.sd_setImage(with: url,placeholderImage:#imageLiteral(resourceName: "placeholderImage"))
}
}
}
if let otherAnswer = data.value(forKey: "cc") {
viewOtherAnswerLabel.text = "View Other Answer \(otherAnswer)"
}
if let ans = data.value(forKey: "comt") as? String{
answered = true
userImageView.frame = CGRect(x: sidePadding/2, y: Int(questionLabel.frame.maxY)+2*sidePaddingForCollectionCells, width: sidePadding, height: sidePadding)
userNameLabel.frame = CGRect(x: 3*sidePadding/2+2*sidePaddingForCollectionCells, y:Int(questionLabel.frame.maxY)+sidePaddingForCollectionCells, width: screenWidth-2*sidePadding, height: Int(topLeftLabel.frame.height))
let newHeight = CommonFunctions.calculateHeight(inString: ans,forFont:answerLabel.font,andWidthOfLabel:answerLabel.frame.width)
let frame = CGRect(x: 3*sidePadding/2+2*sidePaddingForCollectionCells, y:Int(userNameLabel.frame.maxY) + sidePaddingForCollectionCells, width: screenWidth-2*sidePadding-2*sidePaddingForCollectionCells, height: Int(ceil(Float(newHeight))))
answerLabel.frame = frame
answerLabel.text = ans
viewOtherAnswerLabel.frame = CGRect(x: 0, y: Int(answerLabel.frame.maxY)+2*sidePaddingForCollectionCells, width: screenWidth, height: 2*sidePadding/3)
self.addSubview(userImageView)
self.addSubview(userNameLabel)
self.addSubview(answerLabel)
self.addSubview(viewOtherAnswerLabel)
writeAnswerLabel.removeFromSuperview()
return viewOtherAnswerLabel.frame.maxY
}
else{
answered = false
writeAnswerLabel.frame = CGRect(x: 0, y:Int(questionLabel.frame.maxY) + 2*sidePaddingForCollectionCells, width: screenWidth, height: sidePadding)
self.addSubview(writeAnswerLabel)
userImageView.removeFromSuperview()
userNameLabel.removeFromSuperview()
answerLabel.removeFromSuperview()
viewOtherAnswerLabel.removeFromSuperview()
return writeAnswerLabel.frame.maxY
}
}
TableView Code
class GenericView: UIView ,UITableViewDelegate,UITableViewDataSource {
var tableView:UITableView!
var viewFrame = CGRect()
var parentView = ""
var discussViewHeight = [Int:CGFloat]()
var nextUrlPath = ""
var currentUrlPath = ""
private var sliderLabelsText = ["Favourites","Sign In"]
private var tableBlocks = [NSDictionary]()
override init(frame: CGRect) {
super.init(frame: frame)
viewFrame = frame
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if viewFrame != CGRect() {
setup()
}
}
public func updateView(){
viewFrame = self.frame
tableView.frame = (viewFrame)
getRequest()
}
func getRequest(){
currentUrlPath = baseUrl+nextUrlPath
if parentView == discussView{
// let url = baseUrl + nextUrlPath
Alamofire.request(currentUrlPath).responseJSON { response in
if let dict = response.result.value as? [String:AnyObject]{
if (dict["msc"]) as? String == "700", let blocks = dict["blocks"] as? NSArray{
self.nextUrlPath = (dict["next"] as? String ?? "")
for block in blocks{
if let blk = block as? NSDictionary{
if blk.value(forKey: "ty") as? String == "qa"{
self.tableBlocks.append(blk)
}
appDelegate.tableBlocks.append(blk)
}
}
DispatchQueue.main.async(execute: { () -> Void in
self.refreshControl.endRefreshing()
self.tableView.reloadData()
})
}
else{
DispatchQueue.main.async(execute: { () -> Void in
self.currentUrlPath = ""
self.getRequest()
})
}
}
}
return
}
}
func setup(){
backgroundColor = UIColor.white
tableView = UITableView(frame: viewFrame, style: .grouped)
tableView.delegate = self
tableView.dataSource = self
self.addSubview(tableView)
registerCells()
}
//MARK: TableView DataSource Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if parentView == discussView{
return 1
}
return 0
}
func numberOfSections(in tableView: UITableView) -> Int {
if parentView == discussView{
return tableBlocks.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (parentView == discussView){
var cell:QuesAnsFeedTableViewCell? = tableView.dequeueReusableCell(withIdentifier: quesAnsFeedViewCellIdentifier, for: indexPath) as? QuesAnsFeedTableViewCell
if (cell == nil){
cell = QuesAnsFeedTableViewCell(style: .default, reuseIdentifier: quesAnsFeedViewCellIdentifier)
}
cell?.selectionStyle = .none
discussViewHeight[indexPath.section] = (cell?.updateData(data: tableBlocks[indexPath.section]))!
cell?.setNeedsLayout()
cell?.layoutIfNeeded()
return cell!
}
return UITableViewCell()
}
//MARK: TableView Delegate Methods
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if parentView == discussView{
return discussViewHeight[indexPath.section] ?? 0
}
return 0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if parentView == discussView{
return sectionHeaderView
}
return UIView()
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if parentView == discussView && indexPath.section+5 > tableBlocks.count{
if currentUrlPath != baseUrl + nextUrlPath{
getRequest()
}
}
}
}
I have deleted some code from classes just to keep the size of question small.
The call for next fetch will depend on the indexpath of cell which is currently being displayed and the function which fetches the content from server will be getRequest().
Any help is greatly appreciated

Related

CollectionView in TableView Cell Swift mix card type reuse issue

A collection view is contained in a table view cell.
Collection view cells are drawn for each card type.
In indexPath 0 and 1, the card is of a single type.
indexPath 2 is a mix type.
There are three card types, live reserved vod, and playLayer is added when it is a vod type.
When drawing collection view cells in mix type, playLayer is added to reserved type, and playLayer is added to all cells when scrolling up and down.
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
lazy private var homeManager = HomeManager()
var sections: [Section]?
var liveData: [Item]?
var vodData: [Item]?
var mixData: [Item]?
var table: UITableView = {
let tableView = UITableView()
tableView.register(CardCollectionTableViewCell.self, forCellReuseIdentifier: CardCollectionTableViewCell.identifier)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
view.addSubview(table)
homeManager.getdata{ [weak self] response in
self?.sections = response.sections ?? []
self?.liveData = self?.sections?[1].items ?? []
self?.vodData = self?.sections?[2].items ?? []
self?.mixData = self?.sections?[3].items ?? []
self?.table.reloadData()
}
table.delegate = self
table.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
table.frame = view.bounds
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 && liveData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: liveData)
cell.titleLabel.text = sections![1].title!
return cell
} else if indexPath.row == 1 && vodData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: vodData)
cell.titleLabel.text = sections![2].title!
return cell
} else if indexPath.row == 2 && mixData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: mixData)
cell.titleLabel.text = sections![3].title!
return cell
}
else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 400
}
CardCollection TableViewCell
static let identifier = "CardCollectionTableViewCell"
var titleLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text16()
label.textColor = .white
return label
}()
var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
layout.scrollDirection = .horizontal
collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: MyCollectionViewCell.identifier)
collectionView.backgroundColor = .black
return collectionView
}()
var models:[Item]?
func configure(with models: [Item]?) {
self.models = models
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview()
make.leading.equalToSuperview().offset(20)
make.width.equalTo(300)
make.height.equalTo(24)
}
collectionView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(44)
make.leading.equalToSuperview().offset(20)
make.trailing.bottom.equalToSuperview()
}
collectionView.reloadData()
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(collectionView)
contentView.addSubview(titleLabel)
collectionView.delegate = self
collectionView.dataSource = self
contentView.backgroundColor = .black
//guard models != nil else { return }
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Collectionview
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return models?.count ?? 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.identifier, for: indexPath) as! MyCollectionViewCell
cell.setupViews(with: models![indexPath.item])
cell.setupConstraints(with: models![indexPath.item])
cell.configure(with: models![indexPath.item])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 140, height: 350)
}
CollectionViewCell
class MyCollectionViewCell: UICollectionViewCell {
static let identifier = "MyCollectionViewCell"
var player: AVPlayer?
private lazy var imageView: UIImageView = {
let image = UIImageView()
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.backgroundColor = .blue
image.layer.cornerRadius = 8
return image
}()
private lazy var typeLabelBackgroud: UIImageView = {
let image = UIImageView()
image.clipsToBounds = true
image.layer.cornerRadius = 8
return image
}()
private lazy var playerView: AVPlayerLayer? = {
let url = URL(string: "https://1303309272.vod2.myqcloud.com/7e895809vodkr1303309272/8155555e3701925920462082823/f0.mp4")
player = AVPlayer(url: url!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: 0, y: 0, width: 140, height: 210)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.player?.play()
}
return playerLayer
}()
private lazy var typeLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text10()
label.textColor = .white
return label
}()
private lazy var timeLabel: UILabel? = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .white
label.frame.size.width = 42
label.frame.size.height = 16
return label
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = Fonts.text14()
label.textColor = .white
return label
}()
private lazy var storeName: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
return label
}()
private lazy var heartImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "Vector")
image.contentMode = .scaleAspectFit
return image
}()
private lazy var heartCountLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
label.frame.size.width = 27
label.frame.size.height = 16
label.textAlignment = .left
return label
}()
private lazy var eyeImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "Eye")
image.contentMode = .scaleAspectFit
return image
}()
private lazy var eyeCountLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
label.frame.size.width = 27
label.frame.size.height = 16
label.textAlignment = .left
return label
}()
private override init(frame: CGRect) {
super.init(frame: frame)
}
public convenience init() {
self.init(frame:. zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(with model: Item?) {
guard model != nil else {return}
print("CollectionViewCell의 model! data: \(model)")
if model!.type == "LIVE" {
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
} else if model!.type == "RESERVED"{
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
} else if model!.type == "VOD" {
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
addSubview(timeLabel!)
imageView.layer.addSublayer(playerView!)
}
}
func setupConstraints(with model: Item?) {
guard model != nil else {return}
if model!.type == "LIVE" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
} else if model!.type == "RESERVED" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
} else if model!.type == "VOD" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
timeLabel!.snp.makeConstraints { make in
make.top.equalTo(imageView).inset(8)
make.trailing.equalTo(imageView).inset(10)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
}
}
public func configure(with model: Item?) {
//self.model! = model!
guard model != nil else {return}
if model!.type == "LIVE" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "LIVE"
typeLabelBackgroud.backgroundColor = .orange
titleLabel.text = String(model!.title!)
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
} else if model!.type == "RESERVED" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "예정"
typeLabelBackgroud.backgroundColor = Colors.primary()
titleLabel.text = String(model!.title!)
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
} else if model!.type == "VOD" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "VOD"
titleLabel.text = String(model!.title!)
typeLabelBackgroud.backgroundColor = Colors.vodBackgroud()
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
timeLabel?.text = "01:35:40"
}
}
}
The way I tried is let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) ->
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout.init()) .
The reuse problem did not occur, but it cannot be used because the scroll direction is changed.
You could solve your problem in two ways:
1 - reset your cell in cellForItemAt
Currently you call cell.setupViews(with: models![indexPath.item]) for each cell, which adds subviews to the cells. Since collectionView reuses cells, when scrolling you are getting cells which where used as all types (live, reserved, vod), that is why you see that "playLayer is added to all cells when scrolling up and down".
With this code you also add subviews each time the cell is reused, which is also not the best practice.
You could add an additional function to reset the cell and remove all subviews before adding new ones:
cell.subviews.forEach { $0.removeFromSuperview() }
(it is also better to add views to the cell.contentView)
2 - Create separate classes for different cell types
In cellFroItemAtyou could check for the type of the cell and return the required on. Each type will have a different ReuseIdentifier and playLayer will be added only to the type you need

How to detect UILabel (without set width just AutoLayout) is truncate like (Hello I am Test....) or not?

I want to detect UILabel is truncate or not.
And I try a UILabel extension function in stackoverflow and it return true to me.
But the UILabel line just one and no truncated, why return true to me.
Have another function to detect this situation like this.
Have any idea to me to fix this question?
Thanks.
ViewController.swift
import UIKit
import SnapKit
class ViewController: UIViewController {
let tableView = UITableView()
var isExpand: Bool = false
let titleArray: [String] = ["NAME", "AGE", "EMAIL", "TEL", "LOCATION"]
let detailArray: [String] = ["abcdefghijklmnopqrstuvwxyz", "26", "XXXXXX#gmail.com", "XXXXXXXXXXX", "JP"]
let hiddenArray: [Bool] = [false, true, true, false, false]
override func viewDidLoad() {
super.viewDidLoad()
loadUI()
loadLayout()
}
fileprivate func tableviewSetting() {
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.estimatedRowHeight = 70
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.separatorStyle = .none
self.tableView.backgroundColor = .clear
self.tableView.register(TestTableViewCell.self, forCellReuseIdentifier: "TestTableViewCell")
}
fileprivate func loadUI() {
self.tableviewSetting()
self.view.addSubview(tableView)
}
fileprivate func loadLayout() {
tableView.snp.makeConstraints { (make) in
make.top.left.right.bottom.equalToSuperview()
}
}
#objc func expandBtnPressed(sender: UIButton) {
guard sender.tag == 0 else { return }
let indexPath = IndexPath(row: sender.tag, section: 0)
UIView.performWithoutAnimation {
tableView.beginUpdates()
self.isExpand = !isExpand
tableView.reloadRows(at: [indexPath], with: .none)
tableView.endUpdates()
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.titleArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell1 = tableView.dequeueReusableCell(withIdentifier: "TestTableViewCell", for: indexPath) as! TestTableViewCell
cell1.titleLabel.text = self.titleArray[indexPath.row]
cell1.subtitleLabel.text = self.detailArray[indexPath.row]
let bool = cell1.subtitleLabel.isTruncated()
print("bool : \(bool)") // why this return true.
return cell1
}
}
}
extension UILabel {
func countLabelLines() -> Int {
self.layoutIfNeeded()
let myText = self.text! as NSString
let attributes = [NSAttributedString.Key.font : self.font!]
let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil)
return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
}
func isTruncated() -> Bool {
if (self.countLabelLines() > self.numberOfLines) {
print("lines : \(self.countLabelLines())") // print : 2
print("numberOfLines : \(self.numberOfLines)") // print : 1
return true
}
return false
}
}
TestTableViewCell.swift
import UIKit
class TestTableViewCell: UITableViewCell {
let titleLabel: UILabel = { () -> UILabel in
let ui = UILabel()
ui.font = UIFont.systemFont(ofSize: 16)
ui.sizeToFit()
ui.translatesAutoresizingMaskIntoConstraints = false
return ui
}()
let subtitleLabel: UILabel = { () -> UILabel in
let ui = UILabel()
ui.font = UIFont.systemFont(ofSize: 16)
ui.numberOfLines = 1
ui.adjustsFontSizeToFitWidth = false
ui.lineBreakMode = .byTruncatingTail
ui.translatesAutoresizingMaskIntoConstraints = false
return ui
}()
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = .none
loadUI()
loadLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadUI() {
addSubview(titleLabel)
addSubview(subtitleLabel)
}
func loadLayout() {
titleLabel.snp.makeConstraints { (make) in
make.top.equalTo(defaultfifteenPt)
make.left.equalTo(defaultfifteenPt)
make.width.equalTo(defaultNinetyTwoPt)
}
subtitleLabel.snp.makeConstraints { (make) in
make.top.equalTo(titleLabel.snp.top)
make.left.equalTo(titleLabel.snp.right)
make.bottom.equalTo(-defaultfifteenPt)
make.right.equalTo(-defaultfifteenPt)
}
}
}
Hope this help you :
func isTruncated(label: UILabel, containerFrame: CGSize) -> Bool {
let text = label.text ?? ""
let estimatedSize = NSString(string: text).boundingRect(with: .init(width: 100000, height: containerFrame.height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font : label.font!], context: nil)
return estimatedSize.width > containerFrame.width
}
Example:
let sampleLabel1 = UILabel()
sampleLabel1.text = "short text"
isTruncated(label: sampleLabel1, containerFrame: .init(width: 300, height: 15)) // return false
let sampleLabel2 = UILabel()
sampleLabel2.text = "short text fasjfojfosadjaof jasodfi jasodaj
foiasdjfo isadjfoi jasdofj asdojf osiadjfo s"
isTruncated(label: sampleLabel2, containerFrame: .init(width: 300, height: 15)) // return true

How to make the UILabel replace the NavigationBar large title?

I am a beginner to Xcode and Swift and I am currently creating an application where the user adds a person on the application and after that it right the amount of money they owe that person or that person owes him/her.
I actually want to show the user their current balance with other user on NavigationBar Large title and currently I am doing that by using frame where I define the width, height and x,y positions of frame that is replaced by UILabel. However, I wish the balance to be replaced on the NavigationBar Large Title. I am trying to find a solution to this from past 3 days therefore can you please help me? Thanks a lot in advance
import UIKit
class PersonDetailTableViewController: UITableViewController {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var person: People?
var owe: Owe?
#IBOutlet var personTable: UITableView!
var dataInfo: [Owe] = []
var selectedObject: [Owe] = []
var balanceAmount = "Balance: "
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dataInfo.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = personTable
.dequeueReusableCell(withIdentifier: "detailsCell", for: indexPath)
cell.textLabel?.text = dataInfo[indexPath.row].name
cell.detailTextLabel?.text = "₹ \(dataInfo[indexPath.row].amount)"
if dataInfo[indexPath.row].amount < 0 {
cell.detailTextLabel?.textColor = UIColor.red
} else {
cell.detailTextLabel?.textColor = UIColor.green
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedObject = [dataInfo[indexPath.row]]
performSegue(withIdentifier: "addOweDetails", sender: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
getData()
personTable.dataSource = self
addTotalToNav()
print(dataInfo as Any)
}
// MARK: - Table view data source
func addTotalToNav() -> Void {
if let navigationBar = self.navigationController?.navigationBar {
let totalFrame = CGRect(x: 20, y: 0, width: navigationBar.frame.width/2, height: navigationBar.frame.height)
let totalLabel = UILabel()
totalLabel.text = balanceAmount
totalLabel.tag = 1
totalLabel.font = UIFont.boldSystemFont(ofSize: 14)
totalLabel.textColor = UIColor.red
navigationBar.addSubview(totalLabel)
}
}
func getData() -> Void {
do{
dataInfo = try context.fetch(Owe.fetchRequest())
var total:Double = 0.00
for i in 0 ..< dataInfo.count {
total += dataInfo[i].amount as! Double
}
balanceAmount = "Balance: ₹" + (NSString(format: "%.2f", total as CVarArg) as String)
}
catch{
print("Fetching Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! NewOweTableViewController
vc.dataInfo = selectedObject
selectedObject.removeAll()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
personTable.reloadData()
if (self.navigationController?.navigationBar.viewWithTag(1)?.isHidden == true){
self.navigationController?.navigationBar.viewWithTag(1)?.removeFromSuperview()
addTotalToNav()
}
}
}
Swift 3.0 Use below method to create NavigationBarTitle and NavigationBarSubTitle
func setTitle(title:String, subtitle:String) -> UIView {
let titleLabel = UILabel(frame: CGRect(x:0,y: -8 ,width: 0,height: 0))
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.black
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.text = title
titleLabel.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x:0,y:18,width: 0,height :0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.black
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.text = subtitle
subtitleLabel.sizeToFit()
let titleView = UIView(frame: CGRect(x:0,y:0,width : max(titleLabel.frame.size.width, subtitleLabel.frame.size.width),height: 30))
titleView.addSubview(titleLabel)
titleView.addSubview(subtitleLabel)
let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
if widthDiff < 0 {
let newX = widthDiff / 2
subtitleLabel.frame.origin.x = abs(newX)
} else {
let newX = widthDiff / 2
titleLabel.frame.origin.x = newX
}
return titleView
}
Use this in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.titleView = setTitle(title: "My Events", subtitle: "Sub Title")
}
Here is the code, just set the titleView to your label:
let customLabel = UILabel()
// config your label here
navigationItem?.titleView = customLabel
You can use navigationBar.topItem?.titleView = totalLabel instead of navigationBar.addSubview(totalLabel).

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.

iOS: in Swift3, in my collectionView, when I scroll downstair, the collectionView comes automatically at the top. How to stop it?

I would like my collectionView to stop in the cell. The problem is that when I scroll downstair, if I release it, it comes automatically at the first position...
I tried with collection.alwaysBounceVertical = true without success...
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
let layout = OrganiserLayout()
let frameCollection = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height + 1000)
let collection = UICollectionView(frame: frameCollection, collectionViewLayout: layout)
collection.delegate = self
collection.dataSource = self
collection.backgroundColor = UIColor.white
collection.register(OrganiserCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.view.addSubview(collection)
collection.alwaysBounceVertical = true
collection.alwaysBounceHorizontal = true
collection.bounces = true
collection.isPagingEnabled = false
collection.isScrollEnabled = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return 40
}
}
class OrganiserLayout:UICollectionViewLayout {
let cellWidth:CGFloat = 100
var attrDict = Dictionary<IndexPath,UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Here we return the layout attributes for cells in the current rectangle
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in attrDict.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// Here we return one attribute object for the specified indexPath
return attrDict[indexPath]!
}
}
class OrganiserCollectionViewCell:UICollectionViewCell {
var label:UILabel!
var seperator:UIView!
override init(frame: CGRect) {
super.init(frame: frame)
label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(label)
seperator = UIView()
seperator.backgroundColor = UIColor.black
seperator.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(seperator)
let views:[String:UIView] = [
"label":label,
"sep":seperator
]
let cons = [
"V:|-20-[label]",
"V:[sep(1)]|",
"H:|[label]|",
"H:|[sep]|"
]
for con in cons {
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: con, options: [], metrics: nil, views: views))
}
}
I need that because I need the user stops on the cell, and click on it. With that problem, he cannot click on the cells that are downstairs.
Thanks in advance.
Set some height for contentSize like below :
self.contentSize.height = CGFloat(2750)
In your code :
class OrganiserLayout:UICollectionViewLayout {
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
self.contentSize.height = CGFloat(2750) // I added this line
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
}

Resources