I am trying to change the background of the first two cells in my collection view i have tried this code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.frame.width
let height = self.view.frame.height
return CGSize(width: width / 2.2 , height: height / 6)
}
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
MyCollectionView.reloadData()
}
#IBAction func Back(_ sender: Any) {
performSegue(withIdentifier: "fourtothree", sender: nil)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ScoreArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
if indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
return Cell
}
It changes the color of the first two cells which is great. however when I rotate to landscape or scroll it changes the background of different cells not just the first two.
Question: How can I change the background of only the first two cells no mater what the user does?
Since your cell get reused, you need to provide the default color for other cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
} else {
Cell.backgroundColor = UIColor.white //change with your default color
}
return Cell
}
you can change the color of ay cell but as in cellForItemAt indexPath function you are using
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell that statement reuse the cell to reduce the memory usage , So to overcome this problem use
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
}
else {
Cell.backgroundColor = UIColor.clear
}
return Cell
}
Related
Is it possible to set collection view (all items) alpha = 0.5 but header set alpha = 1.0?
If your collection have some interitem or interline spacing and collection view have a background color other than clear or systemBackgroundColor, Then you need to set alpha for background color like this :
yourCollectionView.backgroundColor = UIColor.green.withAlphaComponent(0.5)
you can also use backgroundView of collectionView depending upon the need , like this :
let aView = UIView(frame: yourCollectionView.frame)
aView.backgroundColor = .green
aView.alpha = 0.1
yourCollectionView.backgroundView = aView
and then in cellforItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID", for: indexPath)
cell.contentView.alpha = 0.5
return cell
}
here you can set items alpha:
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell",
for: indexPath
cell.alpha = 0.5
}
here you can set header alpha:
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionView.elementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath)
headerView.backgroundColor = UIColor.blue
headerView.alpha = 1.0 //by default its also 1 just showing here
return headerView
case UICollectionView.elementKindSectionFooter:
break
default:
assert(false, "Unexpected element kind")
}
}
I am trying to change the text size of collection view cell label and works a little bit. When I select item index wise(cell 0, cell 1, cell 2....) it works for me But when I try to select item on random index(like: cell 0 to cell 3) then my app crashes
I'm trying this code:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let idxPath = IndexPath(item: indexPath.item, section: 0)
let cell = collectionView.cellForItem(at: idxPath)
let myCell = collectionView.cellForItem(at: idxPath) as! MenuCell
cell?.isSelected = true
myCell.isSelected = true
myCell.title.font = UIFont.systemFont(ofSize: 16)
collectionView.scrollToItem(at: idxPath, at: UICollectionViewScrollPosition.centeredHorizontally, animated: true)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let idxPath = IndexPath(item: indexPath.item, section: 0)
let myCell = collectionView.cellForItem(at: idxPath) as! MenuCell
myCell.isSelected = false
myCell.title.font = UIFont.systemFont(ofSize: 13)
}
It's working in series cell selection
enter image description here
But when i select cell randomly
enter image description here
Thanks, and sorry for my bad english
Because you recreate IndexPath and then making force unwrap for the cell.
If you have to change font just for first section, so try to change code like this:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if indexPath.section == 0 {
let myCell = collectionView.cellForItem(at: indexPath) as? MenuCell
myCell?.isSelected = false
myCell?.title.font = UIFont.systemFont(ofSize: 13)
}
}
Try this...
var selectedCell = [Int]()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: yourCellIdentifier, for: indexPath) as! MenuCell
//Code for change font size
if selectedCell.contains(indexPath.cell){
cell.title.font = UIFont.systemFont(ofSize: 16)
}else{
cell.title.font = UIFont.systemFont(ofSize: 13)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if selectedCell.contains(indexPath.item){
selectedCell.remove(at: selectedCell.index(of: selectedCell.contains[indexPath.item])!)
}else{
selectedCell.append(indexPath.item)
}
collectionView.reloadData()
}
Im using UIcollection view as my tabbar
when I scroll collection view horizontally previous selected cell will not deselect when i select new one
this is my code to change colour when i select a cell and deselect a cell
var selectedIndexPath : IndexPath = []
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as?
BottomCollectionViewCell {
cell.contentView.backgroundColor = UIColor.orange
cell.backgroundColor = UIColor.orange
}
if let preViousSelectedcell = collectionView.cellForItem(at:
selectedIndexPath) as? BottomCollectionViewCell {
preViousSelectedcell.contentView.backgroundColor=UIColor.purple
preViousSelectedcell.backgroundColor = UIColor.purple
}
selectedIndexPath = indexPath
}
while scrolling cells are reused that time cellForItemAt will call so you need to change some modification in your code
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
YOUR_COLLECTION_VIEW.reloadData()
}
and add below lines inside your collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
if indexPath == selectedIndexPath {
cell.contentView.backgroundColor=UIColor.purple
cell.backgroundColor = UIColor.purple
} else {
cell.contentView.backgroundColor = UIColor.orange
cell.backgroundColor = UIColor.orange
}
Hope this will help you
EDIT: I am trying to re-create the instagram/twitter profile page. So if the current way I am trying to do it won't work, feel free to tell me how to recreate these profile pages in a totally different way.
I have set up a UICollectionView with a header. Inside this header, there is a menuBar that has two different selection options. If the user selects the first index, the menuBar returns 0. If the user selects the second index, the menuBar returns 1.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CoverCell
return cell
}
Here is a picture of the menu bar and the collectionview cells below it:
I also have this code to set up the cells:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let menuBarIndex = profileMenuBarSelectionIndex.menuBarIndexSelection
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test1CellId, for: indexPath) as! test1Cell
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test2CellId, for: indexPath) as! test2Cell
default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test3CellId, for: indexPath) as! test3Cell
}
return cell
}
EDIT 2: I have now added this code, where myTestAction is the delegate function of testAction in a different file.
var index: Int = 0
func testAction() {
index = index == 1 ? 0 : 1
collectionView.reloadData()
}
func myTestAction() {
delegate?.testAction()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch indexPath.row{
case 0:
menuBarIndexSelection = 0
menuBarIndexChangeFlag = 1
case 1:
menuBarIndexSelection = 1
menuBarIndexChangeFlag = 2
case 2:
menuBarIndexSelection = 2
menuBarIndexChangeFlag = 3
default:
menuBarIndexSelection = 0
}
myTestAction()
}
I want to be able to display different cells below the header depending on which value menuBar returns. How would I do this?
OR
How can I recreate the Instagram profile page?
Put a check on cellForRow and supplimentaryViewsForHeader for menuBar value. And when the value of menuBar changes just reload the table. At the time of reloading the data will be shown according to your check present in dataSources.
// MENU BAR BUTTON CLICK
self.collectionView.reloadData()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
if menuBar == 0 {
// show this image
}else{
//show that image
}
return cell
}
Try this,
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Take a variable menuBar. when the user tap change it's value to 0 or 1 and reload collection view when user tap on menu button.
if menuBar == 0 {
return 0
}else{
return 1
}
The reason for getting the compiler error you describe is that you create 4 different variables called "cell":
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
var cell = ...
case 1:
var cell = ...
default:
var cell = ...
}
return cell
The cell instance you return at the end of the function was never assigned a value.
Assigning the first cell variable instead of creating new ones in each case should fix the compiler error:
var cell: UICollectionViewCell
switch menuBarIndex {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test1CellId, for: indexPath) as! test1Cell
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test2CellId, for: indexPath) as! test2Cell
default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: test3CellId, for: indexPath) as! test3Cell
}
return cell
------------------------- EDIT ---------------------
The answer above fixed the compiler error but not the actual question.
I created a small sample project that does what is needed and works fine. Maybe that helps with figuring out the problem. I just created a single view application in Xcode, this is the code for the one view controller in the project and the cells:
class ViewController: UIViewController, UICollectionViewDataSource {
var index: Int = 0
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(frame: CGRect(x: 10, y: 10, width: 200, height: 50))
btn.backgroundColor = .green
btn.setTitle("Change cell color", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.addTarget(self, action: #selector(testAction), for: .touchUpInside)
view.addSubview(btn)
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: CGRect(x: 0, y: 60, width: view.frame.width, height: view.frame.height - 60), collectionViewLayout: layout)
collectionView?.backgroundColor = .white
collectionView?.dataSource = self
collectionView?.register(RedCell.self, forCellWithReuseIdentifier: "red")
collectionView?.register(BlueCell.self, forCellWithReuseIdentifier: "blue")
view.addSubview(collectionView!)
}
func testAction() {
index = index == 1 ? 0 : 1
collectionView?.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: UICollectionViewCell
switch index {
case 0:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "red", for: indexPath)
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "blue", for: indexPath)
default:
cell = UICollectionViewCell()
}
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: 50)
}
}
class RedCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BlueCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I currently have this (pseudo)code:
var selectedCell: UICollectionViewCell?
override func viewDidLoad() {
super.viewDidLoad()
...
#initialize all objects and pull data from the server to fill the cells
UIView.animate(withDuration: 0, animations: {
self.dataCollectionView.reloadData()
}, completion: {(finished) in
let indexPath = IndexPath(row: 0, section: 0)
self.dataCollectionView.selectItem(at: indexPath, animated: true, scrollPosition: .top)
self.collectionView(self.dataCollectionView, didSelectItemAt: indexPath)
})
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! DataCollectionViewCell
if !selectedCell {
cell.layer.borderWidth = 1
}
else {
cell.layer.borderWidth = 2
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAtindexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
selectedCell = cell
cell.image = SomeImageFromServer
cell.layer.borderWidth = 2
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell.layer.borderWidth = 1
}
My thinking is that this code will select the first cell right after the collection view has been loaded, and it does. The problem is it selects the last cell as well, but didSelectItemAtindexPath is never called for the last cell, and only the first cell.
I've tried selecting the second cell by using let indexPath = IndexPath(row: 1, section: 0) and it does select the second cell once the collectionview has been loaded, and the last cell is not selected as you would think.
And once any cell is selected, the last cell is unselected.
So my hypothesis is that this isn't the code thinking the cell is "selected" but that it's for some reason giving the selected cell a "selected cell border" but only when the first selected cell is the first one. Any thoughts?
Try moving the border setting into cell, UICollectionView will automatically manage the border width:
//Swift3
class TestCollectionViewCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
self.layer.borderWidth = 1 //Default border width
}
override var isSelected: Bool {
didSet{
if self.isSelected {
self.layer.borderWidth = 2
}
else{
self.layer.borderWidth = 1
}
}
}
}