I'm having strange issue while scrolling one of my collectionViews. When I'm printing indexPath.row is goes ok from 0..6 but then last indexPath.row is 3, and then if I scroll back it either crashes with excbadadress or prints 1, 2, 4 in random order. I assume that I have and error in my code but really don't understand where is it.
Here is my code:
VC:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
if collectionView == mainEventsCollectionView {
return CGSize(width: UIScreen.main.bounds.width - 40, height: 180)
} else {
return CGSize(width: 150, height: 200)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mainEventsCollectionView {
return 3
} else {
return 7
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == mainEventsCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainEventsCell", for: indexPath) as! MainEventCollectionViewCell
cell.eventTitle.text = "Hello world".uppercased()
cell.setupCell()
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "importantEventsCell", for: indexPath) as! ImportantEventsCollectionViewCell
print(indexPath.row)
cell.setupCell()
return cell
}
}
Cell:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.roundCorners(.allCorners, radius: 6, borderColor: .clear, borderWidth: 0)
}
func setupCell() {
self.content.backgroundColor = colorWithAlpha(.black, alpha: 0.7)
self.eventDate.textColor = .white
self.eventTime.textColor = .white
self.eventName.textColor = .white
if self.content.layer.sublayers!.count > 3 {
self.content.layer.sublayers!.removeLast()
}
if self.eventDate.text == "Today" {
self.content.backgroundColor = .clear
DispatchQueue.main.async(execute: {
self.content.drawGradient(colors: [UIColor(red: 250/255, green: 217/255, blue: 97/255, alpha: 0.7).cgColor, UIColor(red: 255/255, green: 135/255, blue: 67/255, alpha: 0.7).cgColor], locations: [0, 1])
})
self.eventDate.textColor = .black
self.eventTime.textColor = .black
self.eventName.textColor = .black
}
}
Ok, the problem was that I've tried to apply gradient to a UIView, which had elements (UILables). What I had to do is add a subview to the UIView and apply gradient to it.
Related
I am trying to establish a view that I saw in an app. The user get to select an image and can apply filter on the images. The problem is my size for cells are not correct and my collection view would not scroll horizontally.
This is what I expected:
This is what I got so far with the code provided below:
extension SHViewController: UICollectionViewDataSource, UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! SHCollectionViewCell
var filteredImage = smallImage
if indexPath.row != 0 {
filteredImage = createFilteredImage(filterName: filterNameList[indexPath.row], image: smallImage)
}
cell.imageView.image = filteredImage
cell.filterNameLabel.text = filterDisplayNameList[indexPath.row]
updateCellFont()
return cell
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return filterNameList.count
}
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
filterIndex = indexPath.row
if filterIndex != 0 {
applyFilter()
} else {
imageView.image = image
}
updateCellFont()
scrollCollectionViewToIndex(itemIndex: indexPath.item)
}
func updateCellFont() {
// update font of selected cell
if let selectedCell = collectionView.cellForItem(at: IndexPath(row: filterIndex, section: 0)) {
let cell = selectedCell as! SHCollectionViewCell
cell.filterNameLabel.font = UIFont.boldSystemFont(ofSize: 14)
}
for i in 0...filterNameList.count - 1 {
if i != filterIndex {
// update nonselected cell font
if let unselectedCell = collectionView.cellForItem(at: IndexPath(row: i, section: 0)) {
let cell = unselectedCell as! SHCollectionViewCell
if #available(iOS 8.2, *) {
cell.filterNameLabel.font = UIFont.systemFont(ofSize: 14.0, weight: UIFont.Weight.thin)
} else {
// Fallback on earlier versions
cell.filterNameLabel.font = UIFont.systemFont(ofSize: 14.0)
}
}
}
}
}
func scrollCollectionViewToIndex(itemIndex: Int) {
let indexPath = IndexPath(item: itemIndex, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
class SHCollectionViewCell: UICollectionViewCell {
let filterNameLabel: UILabel = {
let label = UILabel()
return label
}()
let imageView: UIImageView = {
let iv = UIImageView()
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
[filterNameLabel, imageView].forEach { addSubview($0) }
filterNameLabel.anchor(top: topAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor)
imageView.anchor(top: filterNameLabel.bottomAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Use UICollectionViewDelegateFlowLayout and return the required cell size like this
extension SHViewController: UICollectionViewDelegateFlowLayout{
return CGSize(width: collectionView.frame.width/4, height: collectionView.frame.height)
}
I have attached this image. You can see the problem here I have implemented the horizontal collection view where cells contains label. When we select the not visible items of the cell (after the first load 4 to 5 items are visible) and reload the cell it always moves to first visible cells.how should I handle the this problem?
func collectionView(
_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"profile_CollectionViewCell_city", for: indexPath as IndexPath) as!
profile_CollectionViewCell
cell.contentView.translatesAutoresizingMaskIntoConstraints = false
if ((self.data_array[indexPath.row] as! NSMutableDictionary)["title"] != nil) {
cell.city_name.text = ((self.data_array[indexPath.row] as! NSMutableDictionary)["title"] as? String)?.uppercased()
}
if (indexPath.row == selectedIndex) {
cell.city_name.textColor = UIColor(red: (0.0 / 255.0), green: (120.0 / 255.0), blue: (56.0 / 255.0), alpha: 1)
cell.city_name.font = UIFont(name: "Poppins-Bold", size: 14)
cell.lower_view.isHidden = false
} else {
cell.city_name.textColor = UIColor(red: (156.0 / 255.0), green: (156.0 / 255.0), blue: (156.0 / 255.0), alpha: 1)
cell.city_name.font = UIFont(name: "Poppins-Light", size: 14)
cell.lower_view.isHidden = true
}
return cell
}
func collectionView(
_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return data_array.count
}
func collectionView(
_ collectionView: UICollectionView,
layoutCollectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath: IndexPath) -> CGSize {
let size = ((self.data_array[indexPath.row] as!
NSMutableDictionary)["title"] as? String)?.size(withAttributes:
nil) ?? CGSize.zero
return size
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath: IndexPath) {
selectedIndex = indexPath.row
self.city_table.reloadData()
}
I want change color of circleView and text in label in cell in CollectionView using function.
Class of my Cell:
class CustomCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
var timerLabel:UILabel = {
let label = UILabel()
label.text = "5"
label.frame = CGRect(x: 200, y: 10, width: 60, height: 60)
label.backgroundColor = .white
label.textAlignment = NSTextAlignment.center
return label
}()
var circleView: UIView = {
let circleView = UIView()
circleView.frame = CGRect(x: 100, y: 10, width: 60, height: 60)
circleView.backgroundColor = .red
circleView.layer.cornerRadius = 30
circleView.layer.masksToBounds = true
return circleView
}()
func setupViews() {
backgroundColor = .white
addSubview(timerLabel)
addSubview(circleView)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
}
Create CollectionView in VC:
func collectionViewSet() {
collectionView?.frame.size.height = (view.frame.height / 100) * 70
collectionView?.backgroundColor = .white
collectionView?.register(CustomCell.self, forCellWithReuseIdentifier: cellId)
}
//-------------- (CollectionView Configure) -------------------
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:view.frame.width ,height: collectionView.frame.height / 6)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId , for: indexPath)
customCell.tag = indexPath.row + 1
return cell
}
And in my created func for example setColor() i want generate ranodm color (by UIColor) for CircleView and generate random number for TimerLable but only in one cell. For next cell I want generate another color and number. Is there any way to do that, i was trying use indexPath.row and func didselectedItemForindexPath but it didn't works at all. Maybe I did something wrong.
Ok I have found an answer. I post my code if someone will have similar problem :)
for x in 0...4{
let indexPath = IndexPath(row: x, section: 0)
guard let cell = collectionView?.cellForItem(at: indexPath) as? CustomCell else {
return
}
cell.circleView.backgroundColor = .blue
}
There are many, many examples of generating random colors and numbers out there - a quick search and you'll have plenty to choose from.
Once you've picked a couple, change your cellForItemAt function to:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId , for: indexPath)
customCell.tag = indexPath.row + 1
let randColor = myRandomColorFunc()
let randNumber = myRandomNumberFunc()
customCell.circleView.backgroundColor = randColor
customCell.timerLabel.text = "\(randNumber)"
return cell
}
I'm facing strange issue. My UICollectionView display half side colums if I scrolling to down.
At first they show perfectly like this
But when I scrolling down, the UICollectionView behave strange and look like this :
Below is my code to populate data to layout (dummy) :
let layoutProduct: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layoutProduct.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layoutProduct.scrollDirection = .vertical
collectionViewProduk = UICollectionView(frame: self.view.frame, collectionViewLayout: layoutProduct)
collectionViewProduk.dataSource = self
collectionViewProduk.delegate = self
collectionViewProduk.register(ProdukPopulerCell.self, forCellWithReuseIdentifier: "ProductCell")
collectionViewProduk.backgroundColor = UIColor(red: 231/255.0, green: 231/255.0, blue: 231/255.0, alpha: 1.0)
self.view.addSubview(collectionViewProduk)
How many data to show :
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewByFilter {
return 4
} else if collectionView == self.collectionViewProduk {
return 8
}
return section
}
How I populate dummy data to cell :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewProduk {
if let cellA = collectionViewProduk.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath) as? ProdukPopulerCell {
cellB.backgroundColor = UIColor.white
if indexPath.row < 8 {
cellB.nameLabel.text = "Product"
cellB.theImageView.image = UIImage(named: "biometric")
cellB.priceLabel.text = "Rp 30.000"
}
return cellB
}
}
return UICollectionViewCell()
}
How I layouting the cell and make them look 2 cell in 1 rows :
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.collectionViewProduk {
let collectionViewSize = collectionViewProduk.frame.size.width - 10
return CGSize(width: collectionViewSize / 2, height: collectionViewSize / 2)
}
return CGSize()
}
Can you guys spot the mistake that I make?
Create a customCollectionViewFlowLayout and apply it to your collectionview
import UIKit
class customCollectionViewFlowLayout: UICollectionViewFlowLayout {
override init() {
super.init()
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
func setupLayout() {
minimumInteritemSpacing = 1
minimumLineSpacing = 1
scrollDirection = .vertical
}
override var itemSize: CGSize {
set {
}
get {
let numberOfColumns: CGFloat = 2
let itemWidth = (self.collectionView!.frame.width - (numberOfColumns - 1)) / numberOfColumns
return CGSize(width:itemWidth, height:itemWidth)
}
}
}
then apply it to your collectionview
yourCollectionView.collectionViewLayout = customCollectionViewFlowLayout()
I have collection view with items, each item has dimension (65 * 65) with horizontal flow, and I have button.
So when I click on the button all items must stack over first item, then I need to make collection layout vertically (like table view).
How to make it (with animation)?
func collectionView(collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if self.isClose {
return CGSizeMake(50, 50)
}else{
if self.isOpen {
return CGSizeMake(320, 50)
}else {
return CGSizeMake(50, 50)
}
}
}
Screenshot
In Swift 3 and 4
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? SSProductCell {
cell.imageView.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? SSProductCell {
cell.imageView.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}