I cannot able to add subview to UItableviewcell - swift

Code
import UIKit
class ViewController:
UIViewController,UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var suma=UITableViewCell()
var sampleviewpurple=UIView(frame: CGRect(x: suma.frame.width/0, y: 0, width: suma.frame.width/2, height: suma.frame.height))
sampleviewpurple.backgroundColor=#colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)
var sampleviewred=UIView(frame: CGRect(x: suma.frame.width/1, y: 0, width: suma.frame.width/2, height: suma.frame.height))
sampleviewred.backgroundColor=#colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
suma.contentView.addSubview(sampleviewpurple)
suma.contentView.addSubview(sampleviewred)
return suma
}
#IBOutlet weak var tab: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tab.dataSource=self
tab.delegate=self
}
}
when I try to add a subview to the suma and return to the delegate, My table view is still blank, I am returning valid data source to the data source when and also noticed the reference to the table view all is fine, But still how I can not able to add a subview to the uitableviewcell

In the cellForRowAt function, you must dequeue your table cell, not instantiate UITableViewCell:
var suma = tableView.dequeueReusableCell(withIdentifier: "YOUR_CELL_IDENTIFIER")

For setting your view's frame you are using the cell's frame which is not set yet. You should use such a view which frame is already set and on which bases you want to calculate the frame of your new views.
Try this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var sumaCell:UITableViewCell?
sumaCell = tableView.dequeueReusableCell(withIdentifier: "sumaCell")
if sumaCell == nil {
sumaCell = UITableViewCell(style: .default, reuseIdentifier: "sumaCell")
}
var sampleviewpurple=UIView(frame: CGRect(x: 0, y: 0, width: ((sumaCell?.frame.width)!/2), height: (sumaCell?.frame.height)!))
sampleviewpurple.backgroundColor=#colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)
var sampleviewred=UIView(frame: CGRect(x: (sumaCell?.frame.width)!/2, y: 0, width: ((sumaCell?.frame.width)!/2), height: (sumaCell?.frame.height)!))
sampleviewred.backgroundColor=#colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
sumaCell?.contentView.addSubview(sampleviewpurple)
sumaCell?.contentView.addSubview(sampleviewred)
return sumaCell!
}

You are creating the cell in code. First of all, you have to register the UITableViewCell in viewDidLoad method.
tab.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")
Then you have to use the dequeue cell in cellForRowAt method.
var suma = tab.dequeueReusableCell(withIdentifier: "DefaultCell")
If you are instantiating the cell from storyboard, you just have to use dequeue cell. No need to register.

I made three change.
Dequeue the cell for reusability.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var suma = UITableViewCell()
suma = tab.dequeueReusableCell(withIdentifier: "DefaultCell")!`
Changed the sampleviewpurple and sampleviewred x position
let sampleviewpurple = UIView(frame: CGRect(x: 0, y: 0, width: suma.frame.width/2, height: suma.frame.height))
let sampleviewred = UIView(frame: CGRect(x: suma.frame.width/2, y: 0, width: suma.frame.width/2, height: suma.frame.height))
Registered the cell which is created programmatically to create a connection between UITableView and UITableViewCell in viewDidLoad function
tab.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")

Related

TableView Cells scroll over headerview in UITableViewController

so I currently have a TableViewController that has headerview and prototype cells. Inside the headerview, there is an image. I have programmed it to where a user scrolls down, the headerview stretches down. But I want to find a way to make that header view stick where it is at and when a user scrolls up on the table view, the cells go over the headerview instead of the headerview scrolling up with the cells which it currently is doing. Here is my code for the TableViewController:
import UIKit
class HeaderViewTableViewController: UITableViewController {
var image: UIImageView?
var image2: UIImageView?
var songNameArray = ["Intro", "The Box", "Start wit Me (feat. Gunna)", "Perfect Time", "Moonwalkin (feat. Lil Durk)", "Big Stepper", "Gods Eyes", "Peta (feat. Meek Mill)", "Boom Boom Boom", "Elyse's Skit", "High Fashion (feat. Mustard)", "Bacc Seat (feat. Ty Dolla $ign)", "Roll Dice", "Prayers to the Trap God", "Tip Toe (feat. A Boogie wi da Hoodie)", "War Baby"]
private let tableHeaderViewHeight: CGFloat = 350.0
private let tableHeaderViewCutAway: CGFloat = 0.1
var headerView: HeaderView!
var headerMaskLayer: CAShapeLayer!
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
headerView = tableView.tableHeaderView as! HeaderView
headerView.imageView = image
tableView.tableHeaderView = nil
tableView.addSubview(headerView)
tableView.contentInset = UIEdgeInsets(top: tableHeaderViewHeight, left: 0, bottom: 0, right: 0)
tableView.contentOffset = CGPoint(x: 0, y: -tableHeaderViewHeight + 64)
//cut away header view
headerMaskLayer = CAShapeLayer()
headerMaskLayer.fillColor = UIColor.black.cgColor
headerView.layer.mask = headerMaskLayer
let effectiveHeight = tableHeaderViewHeight - tableHeaderViewCutAway/2
tableView.contentInset = UIEdgeInsets(top: effectiveHeight, left: 0, bottom: 0, right: 0)
tableView.contentOffset = CGPoint(x: 0, y: -effectiveHeight)
updateHeaderView()
}
func updateHeaderView() {
let effectiveHeight = tableHeaderViewHeight - tableHeaderViewCutAway/2
var headerRect = CGRect(x: 0, y: -effectiveHeight, width: tableView.bounds.width, height: tableHeaderViewHeight)
if tableView.contentOffset.y < -effectiveHeight {
headerRect.origin.y = tableView.contentOffset.y
headerRect.size.height = -tableView.contentOffset.y + tableHeaderViewCutAway/2
}
headerView.frame = headerRect
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y:0))
path.addLine(to: CGPoint(x: headerRect.width, y: 0))
path.addLine(to: CGPoint(x: headerRect.width, y: headerRect.height))
path.addLine(to: CGPoint(x: 0, y: headerRect.height - tableHeaderViewCutAway))
headerMaskLayer?.path = path.cgPath
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.tableView.decelerationRate = UIScrollView.DecelerationRate.fast
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
#IBAction func backButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
extension HeaderViewTableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return songNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SongCell", for: indexPath) as! SongNameTableViewCell
cell.songName.text = songNameArray[indexPath.row]
return cell
}
}
extension HeaderViewTableViewController {
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
updateHeaderView()
}
}
Any idea on how to achieve this? Also I have a button nested inside the headerview that I would like to stick to the top of the view controller when users scroll up. I have it nested there because I'm not sure where else it could go in a table view like a custom cell.
Heres an image of how it is setup in my storyboard and what it looks like when ran on the simulator.

How Can I Get distance between Cell(Top, Bottom, Left, right)

I Want to add distance between cells(Top and bottom) and distance between cells and table view's walls(left, right): I need to do it using by UIEdgeInset, not by adding headerView to cell:
// Inside UITableViewCell subclass
override func layoutSubviews() {
super.layoutSubviews()
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
}
Swift 4.2
override func layoutSubviews() {
super.layoutSubviews()
//set the values for top,left,bottom,right margins
let margins = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
contentView.frame = contentView.frame.inset(by: margins)
}
In cellforRowat populate data according to section like indexPath.section. and add below method
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: self.myTableView.frame.width, height: 10))
headerView.backgroundColor = UIColor.clear
return headerView
}

UITableView header UITableViewAutomaticDimension not working

I want to make my tableview header have automatic height because I have label in my header view that can have multi line text.
I've set following steps:
in view did load ad
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 200
}
But it still not working.
Here is my storyboard configuration (I have set lines to 0 and line break to word wrap.
Another question: Is the custom view I added on the top of TableViewCell is a header cell?
I've ended up using method to calculate height for label and added the height to the View.
private func heightForView(text: String, font: UIFont, width: CGFloat) -> CGFloat {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
In the viewDidLoad()
let labelHeight = heightForView(text: post.content, font: contentLabel.font, width: contentLabel.frame.width)
headerView.frame.size.height = headerView.frame.size.height + labelHeight
Still curious why the UITableViewAutomaticDimension not working in this case.

How to change UITableView section borders?

I have a UITableView and I simply want to set the same width to all separators. I already know something about customizing uitableview, but this one is a mystery to me..
Basically, I want to set this section headers separators to be the same width as cell separators, have the same leading space to the superview. What's the best way to do it?
EDIT
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.textLabel?.font = header.textLabel?.font.withSize(12)
header.textLabel?.textColor = ColorConstants.symbolsColor
}
In the table view method CellForRowAt...
Try adding this code
cell.preservesSuperviewLayoutMargins = false
cell.seperatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
Headers and footers don't have separator lines but you can mock them using custom UIViews and putting them in:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
let px = 1 / UIScreen.main.scale
let frame = CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: px)
let line = UIView(frame: frame)
view.addSubview(line)
line.backgroundColor = self.tableView.separatorColor
self.tableView.tableHeaderView = view
}
And add your other code to this function as well instead of willDisplayHeaderView.
You may need to adjust the CGRect dimensions to match what you want exactly. I believe the default cell separators start at 15 points (not 100% sure on that)
credit to: https://stackoverflow.com/a/28177407/7535093

UIView in custom UITableViewCell redraws when scrolling

I am adding an UIView inside my custom UITableView to draw more or less like an availability bar. I have two problems with it:
1.- The view only gets drawn when the new cells appear on screen not at launch time as you can see in the GIF below.
2.- When scrolling tableView several times the UIView on each cell is redrawn so they overlap with each other
GIF
Code of UITableViewCell :
import UIKit
class CustomTableViewcell: UITableViewCell {
#IBOutlet weak var bikeStationLabel: UILabel!
#IBOutlet weak var progressView: UIView!
#IBOutlet weak var distanceLabel: UILabel!
override internal func awakeFromNib() {
}
}
I think nothing is wrong there, it's simple. My problem I think comes with the func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method. What I have so far is:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomTableViewcell! = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewcell
cell.backgroundColor = UIColor(red: 120/255, green: 120/255, blue: 120/255, alpha: 0.5)
// Dump the data into a single variable to shorten the code
let stations = parsedData[indexPath.row]
// Draw a rectangle on each progress bar depending on the availability of the bikes
let availabilityGraph = UIBezierPath(roundedRect: CGRect(x: cell.progressView.frame.minX, y: cell.progressView.frame.minY, width: CGFloat(Float(stations.freeBikes!) / (Float(stations.freeBikes!) + Float(stations.freeDocks!))) * cell.progressView.frame.width, height: cell.progressView.frame.height), cornerRadius: 0)
let shapeLayer = CAShapeLayer()
shapeLayer.path = availabilityGraph.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear().cgColor
//you can change the line width
shapeLayer.lineWidth = cell.frame.height
shapeLayer.strokeColor = UIColor(red: 96/255, green: 96/255, blue: 96/255, alpha: 0.8).cgColor
cell.progressView.layer.addSublayer(shapeLayer)
cell.bikeStationLabel.textColor = UIColor.white()
cell.bikeStationLabel.text = stations.stationName!
cell.distanceLabel.text = "100 m"
return cell
}
First of all give your layer specific name like this
shapeLayer.name = "ShapeLayer"
Now before adding it the progressView check that layer is not already added in the progressView, if added then just remove it.
if let sublayers = cell.progressView.layer.sublayers {
for layer: CALayer in sublayers {
if (layer.name == "ShapeLayer") {
layer.removeFromSuperlayer()
break
}
}
}
//Now add the layer to `progressView`
cell.progressView.layer.addSublayer(shapeLayer)