me2 me2 - 4 years ago 131
iOS Question

Setting a gradient background in UITableViewCell

im trying to create a tableview controller where every cell has a gradient as background.

So my approach was the code below, it sets the correct colors but when scrolling the colors appear as they were set randomly.

I dont know where the error is.
The textLabels will be set properly but the colors not.

import UIKit


class ResourceOverViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let reuseIdentifier = "OverViewCell"
@IBOutlet weak var prototypeCell: UITableViewCell!
@IBOutlet weak var tableView:UITableView!
var resourceInMissions:[ResourceInMission] = [ResourceInMission]()
var whiteRussian:Int64 = Int64()
var Caipirinha:[String] = [String]()
var Avails:[CAGradientLayer] = [CAGradientLayer]()


override func viewDidLoad() {
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
super.viewDidLoad()

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source


override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setView()

}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return Caipirinha.count
}


func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print(indexPath)

cell.textLabel?.backgroundColor = UIColor.clear
cell.textLabel?.isOpaque = true
cell.isOpaque = true

var gradient = Avails[indexPath.row]
gradient.frame = cell.bounds

cell.textLabel?.layer.insertSublayer(gradient, at: 0)

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
cell.textLabel?.text = Caipirinha[indexPath.row]

return cell
}



func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
var index: IndexPath = indexPath
let cell = tableView.cellForRow(at: indexPath)
whiteRussian = resourceInMissions[indexPath.row].getID()



guard let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewController(withIdentifier: "ShowResource") as UIViewController? else {
print("Could not instantiate view controller with identifier of type SecondViewController")
return
}

vc.setObjectID(idToTransfer: whiteRussian)
present(vc, animated:true, completion: nil)

}

@IBAction func back(){
//Code is in Extension of UIViewController
moveBack()

}

func sort(resourceInMissions:[ResourceInMission]) -> [ResourceInMission] {

var arrayOfArrays = [[ResourceInMission](), [ResourceInMission](), [ResourceInMission](), [ResourceInMission](), [ResourceInMission](), [ResourceInMission]()]
// At first take the availability to sort.
// It produces availibility lists
for element in resourceInMissions {


// gets the index of the avail. from availibilities array
// for every avail a new list is made in arraysOfArray


if let string = element.getAvailability(){
if let av = availibilitys.index(of: string){

arrayOfArrays[av].append(element)

}
}

}



// Now iterate through each list and sort for the resourceType
// Idea is: get rsIM from one of the arrays above and put it in a type array for each element
// after finishing the avail array merge all type arrays for avail list sorted for types
var arraySorted:[ResourceInMission] = [ResourceInMission]()
for array in arrayOfArrays {

// lists have to be initialized for each loop
// otherwise the lists would be merged
var type1:[ResourceInMission] = [ResourceInMission]()
var type2:[ResourceInMission] = [ResourceInMission]()
var type3:[ResourceInMission] = [ResourceInMission]()
var type4:[ResourceInMission] = [ResourceInMission]()
var type5:[ResourceInMission] = [ResourceInMission]()
var type6:[ResourceInMission] = [ResourceInMission]()
var type7:[ResourceInMission] = [ResourceInMission]()
var type8:[ResourceInMission] = [ResourceInMission]()

for element in array {

if let id = element.getResourceID(){
if let resource = Resource().getByIdFromDB(id: id){
if let typeID = resource.getResourceTypeID(){

switch typeID {
case 1:
type1.append(element)
break
case 2:
type2.append(element)
break
case 3:
type3.append(element)
break
case 4:
type4.append(element)
break
case 5:
type5.append(element)
break
case 6:
type6.append(element)
break
case 7:
type7.append(element)
break
case 8:
type8.append(element)
break
default:
break
}
}
}
}
}

arraySorted = arraySorted + type1 + type2 + type3 + type4 + type5 + type6 + type7 + type8


}
return arraySorted
}

func setView(){
var count = 0


resourceInMissions = [ResourceInMission]()
resourceInMissions = try! ResourceInMission().getOverviewList()
count = resourceInMissions.count


resourceInMissions = sort(resourceInMissions: resourceInMissions)

Caipirinha = [String]()
Avails = [CAGradientLayer]()
Caipirinha.removeAll()
for index in 0 ..< resourceInMissions.count {
Caipirinha.append(resourceInMissions[index].toString())
let gradient: CAGradientLayer = CAGradientLayer()

if let av = resourceInMissions[index].getAvailability(){

switch av {
case availibilitys[0]:
//blue
let blue = [hexStringToUIColor(hex: "#E5EEFF"), hexStringToUIColor(hex: "#93B7FF"), hexStringToUIColor(hex: "#4F8EFF")]
gradient.colors = blue.map { $0.cgColor }
Avails.append(gradient)
break
case availibilitys[1]:
//red
let red = [hexStringToUIColor(hex: "#FFE5E5"), hexStringToUIColor(hex: "#FF8E8B"), hexStringToUIColor(hex: "#FF4F4F")]
gradient.colors = red.map { $0.cgColor }
Avails.append(gradient)
break
case availibilitys[2]:
//rose
let rose = [hexStringToUIColor(hex: "#FFFFFF"), hexStringToUIColor(hex: "#FDEADA"), hexStringToUIColor(hex: "#FAC090")]
gradient.colors = rose.map { $0.cgColor }
Avails.append(gradient)
break
case availibilitys[3]:
//yellow
let yellow = [hexStringToUIColor(hex: "#F5FFE6"), hexStringToUIColor(hex: "#F0FB85"), hexStringToUIColor(hex: "#FBF622")]
gradient.colors = yellow.map { $0.cgColor }
Avails.append(gradient)
break
case availibilitys[4]:
//green
let green = [hexStringToUIColor(hex: "#F5FFE6"), hexStringToUIColor(hex: "#C8FB85"), hexStringToUIColor(hex: "#BCFB5F")]
gradient.colors = green.map { $0.cgColor }
Avails.append(gradient)
break
case availibilitys[5]:
//grey
let gray = [hexStringToUIColor(hex: "#F2F2F2"), hexStringToUIColor(hex: "#E9E9E9"), hexStringToUIColor(hex: "D9D9D9")]
gradient.colors = gray.map { $0.cgColor }
Avails.append(gradient)
break
default:
break
}
}


}
self.tableView.reloadData()
}
}

Answer Source

The reason your gradients appear random is because of cell re-use.

cell.textLabel?.layer.insertSublayer(gradient, at: 0)

This line is getting called every time you display a cell, so it works the first time but as your cells get reused the new gradients are just getting added behind the old ones.

You can either remove the old gradient layer before adding a new one, or create a UITableViewCell subclass with a gradient layer that can be updated.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download