Related
I have a tableview whose height is dynamically adjusted. The height is adjusted so that the tableview only includes a certain number of rows, and no empty rows. So, if there are only 2 rows then the height is smaller, and if there are 4 rows then the height is bigger. However, I do not want its height to go past a certain point. How can I allow the height to be dynamically adjusted, while not letting the height ever reach past a certain point?
This is my code:
#IBOutlet var tableView: UITableView!
#IBOutlet var tableViewHeightConstraint: NSLayoutConstraint!
var items: [String] = ["Swift", "Is", "So", "Amazing"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "Cell") as! UITableViewCell
// Make sure the table view cell separator spans the whole width
cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
override func viewWillAppear(_ animated: Bool) {
// Adjust the height of the tableview
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: tableView.contentSize.height)
// Add a border to the tableView
tableView.layer.borderWidth = 1
tableView.layer.borderColor = UIColor.black.cgColor
print("We ran ViewWillAppear")
}
// This function is used for adjusting the height of the tableview
override func viewDidLayoutSubviews(){
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: tableView.contentSize.height)
tableView.reloadData()
}
// Allow cell deletion in tableview
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
// delete item at indexPath
self.items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height - 44
print(self.items)
print("Number of rows: \(tableView.numberOfRows(inSection: 0))")
}
delete.backgroundColor = UIColor.blue
return [delete]
}
In viewWillAppear , you can try
let limit:CGFloat = 900.0
if tableView.contentSize.height < limit {
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: tableView.contentSize.height)
}
else {
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: limit )
}
Or set value to
tableViewHeightConstraint.constant = ( tableView.contentSize.height < limit ) ? tableView.contentSize.height : limit
self.view.layoutIfNeeded()
I have a cell in a tableview that contains a horizontal paging collection view.
Inside each page of this collection view there is a vertical collection view.
In order to avoid a "scroll-in-scroll" problem, I disabled vertical scrolling in the vertical collection views.
The vertical collection view's cell count is not static and can be any number.
So this creates a problem: the collection view (you'll have to ask me for clarification about which one) won't fit properly into the table view's cell anymore.
To solve this, I changed the table view's cell height by changing the constraints in the storyboard... but the problem remains.
Here is an image to help illustrate the problem:
and here is my code:
class myTBViewController: UITableViewController , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 10 {
return 2
} else {
return 30
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 10 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainPages", for: indexPath) as! mainPages
cell.backgroundColor = UIColor.yellow
cell.listCV.clipsToBounds = true
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "showAdvCell", for: indexPath) as! showAdvCell
cell.backgroundColor = UIColor.red
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
if collectionView.tag == 10 {
let collectionViewHeight = collectionView.frame.height
let itemsHeight = collectionView.contentSize.height
let topInset = ( collectionViewHeight - itemsHeight ) / 4
return UIEdgeInsetsMake(topInset ,0, 0 , 0)
} else {
let collectionViewHeight = collectionView.frame.height
let itemsHeight = CGFloat(80)
let topInset = ( collectionViewHeight - itemsHeight ) / 4
return UIEdgeInsetsMake(topInset ,0, 0 , 0)
}
}
var headerSegment = UISegmentedControl()
override func viewDidLoad() {
super.viewDidLoad()
headerSegment.frame = CGRect(x: 0, y: 200, width: UIScreen.main.bounds.width, height: 30)
let items = ["فروشگاه ها", "دیوار"]
headerSegment = UISegmentedControl(items: items)
headerSegment.selectedSegmentIndex = 0
headerSegment.addTarget(self, action: #selector(selectPage), for: UIControlEvents.valueChanged)
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200)
let headerImageView = UIImageView(frame: frame)
let image: UIImage = UIImage(named: "1")!
headerImageView.image = image
let frame3 = CGRect(x: 0, y: 0, width: 80, height: 80)
let headerImageView2 = UIImageView(frame: frame3)
let image2: UIImage = UIImage(named: "1")!
headerImageView2.image = image2
headerSegment.addSubview(headerImageView2)
headerSegment.bringSubview(toFront: headerImageView2)
headerImageView2.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: 200)
headerSegment.frame = CGRect(x: 0, y: 200, width: UIScreen.main.bounds.width + 10 , height: 40)
headerSegment.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: 200)
let mainView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 230))
let headerSegmentView = UIView(frame : CGRect(x: 0, y: 200, width: UIScreen.main.bounds.width, height: 40))
headerSegmentView.center = headerSegment.center
headerSegmentView.backgroundColor = UIColor.white
mainView.addSubview(headerImageView)
mainView.bringSubview(toFront: headerImageView)
mainView.addSubview(headerSegmentView)
mainView.bringSubview(toFront: headerSegmentView)
mainView.addSubview(headerSegment)
mainView.bringSubview(toFront: headerSegment)
mainView.addSubview(headerImageView2)
mainView.bringSubview(toFront: headerImageView2)
self.tableView.tableHeaderView = mainView
headerImageView2.layer.borderWidth = 2
headerImageView2.layer.masksToBounds = false
headerImageView2.layer.borderColor = UIColor.init(white: 255/255, alpha: 0.3).cgColor
headerImageView2.layer.cornerRadius = headerImageView2.frame.height/2
headerImageView2.clipsToBounds = true
}
#objc func selectPage() {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "myTBViewCell") as! myTBViewCell
switch headerSegment.selectedSegmentIndex {
case 0:
print("0")
cell.myTBCollectionView.scrollToItem(at:IndexPath(item: 0, section: 0), at: .top, animated: false)
case 1:
print("1")
cell.myTBCollectionView.scrollToItem(at:IndexPath(item: 1, section: 0), at: .top, animated: false)
default:
print("0")
cell.myTBCollectionView.scrollToItem(at:IndexPath(item: 0, section: 0), at: .top, animated: false)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
tableView.estimatedRowHeight = 200
tableView.rowHeight = UITableViewAutomaticDimension
return 600
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "myTBViewCell", for: indexPath) as! myTBViewCell
return cell
}
}
I have a similar Problem , finally, I have solved it by creating a height Constraint of CollectionView.
than setting CollectionView height Constraint based on CollectionView ContentSize.
self.collectionViewHeight.constant = self.recentCollectionView.collectionViewLayout.collectionViewContentSize.height
the alternative approach is to override systemLayoutSizeFitting method of tableViewCell
ex:
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
self.tagCollectionView.layoutIfNeeded()
return self.tagCollectionView.collectionViewLayout.collectionViewContentSize
}
in addition you don't need to return fixed 600 height in your table view delegate heightForRowAtIndexPath
I have a UITableViewController and UITableViewCell. Now I am try to access a view from a UITableViewCell to UITableViewController by didSelectRowAt function. But I could not do it.
TableViewController
import Foundation
import UIKit
class FlipViewCon: UIViewController, UITableViewDelegate, UITableViewDataSource{
let flipCellId = "flipCellid"
let flipTableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .green
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .gray
flipTableView.delegate = self
flipTableView.dataSource = self
flipTableView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.addSubview(flipTableView)
flipTableView.register(FlipTableViewCell.self, forCellReuseIdentifier: flipCellId)
}
let countryArray = ["bangladesh", "nepal", "china", "malaysia", "thai land", "japan", "England", "canada"]
let cityArray = ["Dhake","Kathmandu", "Beijing", "Kuala Lumpur", "Bangkok", "tokeyo", "London", "Torento"]
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: flipCellId, for: indexPath) as! FlipTableViewCell
//cell.textLabel?.text = countryArray[indexPath.row]
cell.zeroLabel.text = countryArray[indexPath.row]
cell.oneLabel.text = cityArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UIView.transition(with: FlipTableViewCell.zeroView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
FlipTableViewCell.zeroView.isHidden = true
FlipTableViewCell.oneView.isHidden = false
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
UIView.transition(with: FlipTableViewCell.oneView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
FlipTableViewCell.zeroView.isHidden = false
FlipTableViewCell.oneView.isHidden = true
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.flipTableView.frame.width / 4
}
}
TableViewCell
import UIKit
class FlipTableViewCell: UITableViewCell{
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static let zeroView = flipView(myColor: .yellow)
static let oneView = flipView(myColor: .green)
static func flipView(myColor: UIColor) -> UIView {
let view = UIView()
view.backgroundColor = myColor
return view
}
let zeroLabel: UILabel = {
let lb = UILabel()
lb.text = "Zero 0"
return lb
}()
let oneLabel: UILabel = {
let lb = UILabel()
lb.text = "one 1"
return lb
}()
func setupView(){
FlipTableViewCell.zeroView.frame = CGRect(x: 0, y: 0, width: frame.width, height:frame.height)
FlipTableViewCell.oneView.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
self.addSubview(FlipTableViewCell.zeroView)
self.addSubview(FlipTableViewCell.oneView)
zeroLabel.frame = CGRect(x: 20, y: 0, width: self.frame.width - 40, height: 50)
oneLabel.frame = CGRect(x: 20, y:0, width: self.frame.width - 40, height: 50)
addSubview(zeroLabel)
addSubview(oneLabel)
}
}
Try this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
UIView.transition(with: cell.zeroView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
cell.zeroView.isHidden = true
cell.oneView.isHidden = false
}
}
Edit
I have update your FlipTableViewCell
it looks like this
class FlipTableViewCell: UITableViewCell{
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var zeroView : UIView!
var oneView : UIView!
func flipView(myColor: UIColor) -> UIView {
let view = UIView()
view.backgroundColor = myColor
return view
}
let zeroLabel: UILabel = {
let lb = UILabel()
lb.text = "Zero 0"
return lb
}()
let oneLabel: UILabel = {
let lb = UILabel()
lb.text = "one 1"
return lb
}()
func setupView(){
zeroView = flipView(myColor: .yellow)
oneView = flipView(myColor: .green)
zeroView.frame = CGRect(x: 0, y: 0, width: frame.width, height:frame.height)
oneView.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
self.addSubview(zeroView)
self.addSubview(oneView)
zeroLabel.frame = CGRect(x: 20, y: 0, width: self.frame.width - 40, height: 50)
oneLabel.frame = CGRect(x: 20, y:0, width: self.frame.width - 40, height: 50)
addSubview(zeroLabel)
addSubview(oneLabel)
}
}
And Change some code in FlipViewCon
class FlipViewCon: UIViewController, UITableViewDelegate, UITableViewDataSource{
let flipCellId = "flipCellid"
let flipTableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .green
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .gray
flipTableView.delegate = self
flipTableView.dataSource = self
flipTableView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.addSubview(flipTableView)
flipTableView.register(FlipTableViewCell.self, forCellReuseIdentifier: flipCellId)
}
let countryArray = ["bangladesh", "nepal", "china", "malaysia", "thai land", "japan", "England", "canada"]
let cityArray = ["Dhake","Kathmandu", "Beijing", "Kuala Lumpur", "Bangkok", "tokeyo", "London", "Torento"]
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: flipCellId, for: indexPath) as! FlipTableViewCell
//cell.textLabel?.text = countryArray[indexPath.row]
cell.zeroLabel.text = countryArray[indexPath.row]
cell.oneLabel.text = cityArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
UIView.transition(with: cell.zeroView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
cell.zeroView.isHidden = true
cell.oneView.isHidden = false
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
UIView.transition(with: cell.zeroView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
cell.zeroView.isHidden = false
cell.oneView.isHidden = true
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.flipTableView.frame.width / 4
}
}
Edit2
Replace this method in above solution
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
UIView.transition(with: cell.oneView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
cell.zeroView.isHidden = false
cell.oneView.isHidden = true
}
}
Hope it will work for you
Do like this
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! FlipTableViewCell
// TODO:
}
Just like all the other answers on this post, use the cellForRow(at: IndexPath) method on UITableView, to get a reference to the cells in the table view.
This method returns a UITableViewCell, if the cell is loaded (visible) and nil if the indexPath is not correct or the cell is not loaded.
The code should look like:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
// Do something with cell.
}
TableViewController
import Foundation
import UIKit
class FlipViewCon: UIViewController, UITableViewDelegate, UITableViewDataSource{
let flipCellId = "flipCellid"
let flipTableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .green
tableView.allowsMultipleSelection = true
return tableView
}()
let countryArray = ["India","bangladesh", "nepal", "china", "malaysia", "thai land", "japan", "England", "canada"]
let cityArray = ["Delhi","Dhake","Kathmandu", "Beijing", "Kuala Lumpur", "Bangkok", "tokeyo", "London", "Torento"]
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .gray
flipTableView.delegate = self
flipTableView.dataSource = self
flipTableView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.addSubview(flipTableView)
self.resetFlag()
flipTableView.register(FlipTableViewCell.self, forCellReuseIdentifier: flipCellId)
}
var flagArray : [String] = []
func resetFlag() {
flagArray.removeAll(keepingCapacity: true)
for _ in 0 ..< self.countryArray.count {
self.flagArray.append("0")
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: flipCellId, for: indexPath) as! FlipTableViewCell
cell.selectionStyle = .none
if flagArray[indexPath.row] == "0" {
cell.zeroView.isHidden = false
cell.oneView.isHidden = true
}else{
cell.zeroView.isHidden = true
cell.oneView.isHidden = false
}
cell.zeroLabel.text = countryArray[indexPath.row]
cell.oneLabel.text = cityArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
self.flagArray.remove(at: indexPath.row)
self.flagArray.insert("1", at: indexPath.row)
UIView.transition(with: cell.zeroView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: { (complete) in
cell.zeroView.isHidden = true
cell.oneView.isHidden = false
})
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? FlipTableViewCell {
self.flagArray.remove(at: indexPath.row)
self.flagArray.insert("0", at: indexPath.row)
UIView.transition(with: cell.oneView, duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: { (complete) in
cell.zeroView.isHidden = false
cell.oneView.isHidden = true
})
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.flipTableView.frame.width / 4
}
}
TableViewCell
import UIKit
class FlipTableViewCell: UITableViewCell{
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let zeroView = flipView(myColor: .yellow)
let oneView = flipView(myColor: .green)
static func flipView(myColor: UIColor) -> UIView {
let view = UIView()
view.backgroundColor = myColor
return view
}
let zeroLabel: UILabel = {
let lb = UILabel()
lb.text = "Zero 0"
return lb
}()
let oneLabel: UILabel = {
let lb = UILabel()
lb.text = "one 1"
return lb
}()
func setupView(){
zeroView.frame = CGRect(x: 0, y: 0, width: frame.width, height:frame.width/4)
oneView.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.width/4)
self.addSubview(oneView)
self.addSubview(zeroView)
zeroLabel.frame = CGRect(x: 20, y: (frame.width/4)/2 - 25, width: self.frame.width - 40, height: 50)
oneLabel.frame = CGRect(x: 20, y:(frame.width/4)/2 - 25, width: self.frame.width - 40, height: 50)
zeroView.addSubview(zeroLabel)
oneView.addSubview(oneLabel)
}
}
I am developing a custom tableView with stretchy headerView and it also has sticky headerView.
I have successfully achieved it by updating its contentInset and contentOffset properties. But after updating its contentInset the scroll becomes jerky.
Below is the code for the same:
I have added below code in viewDidLoad method of viewController.and called another method updateHeaderView to update headerView Height and y position. And kTableHeaderHeight is the constant tableView header height.
headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: kTableHeaderHeight))
headerView = tableView.tableHeaderView
tableView.tableHeaderView = nil
tableView.addSubview(headerView)
tableView.contentInset = UIEdgeInsets(top: kTableHeaderHeight, left: 0, bottom: 0, right: 0)
tableView.contentOffset = CGPoint(x: 0, y: -kTableHeaderHeight)
In updateHeaderView method I have added code:
var headerRect = CGRect(x: 0, y: -kTableHeaderHeight, width: tableView.bounds.width, height: kTableHeaderHeight)
var insetTop: CGFloat = 0
if tableView.contentOffset.y < -kTableHeaderHeight {
headerRect.origin.y = tableView.contentOffset.y
headerRect.size.height = -tableView.contentOffset.y
insetTop = kTableHeaderHeight
}else if tableView.contentOffset.y >= 0 {
insetTop = 0
}else if tableView.contentOffset.y <= 0{
insetTop = -tableView.contentOffset.y
}
tableView.contentInset = UIEdgeInsets(top: insetTop, left: 0, bottom: 0, right: 0)
tableView.scrollIndicatorInsets = UIEdgeInsets(top: insetTop, left: 0, bottom: 0, right: 0)
headerView.frame = headerRect
And called above method from scrollView's delegate method scrollviewDidScroll.
After doing all this stuff the sticky and stretchy tableView behavior is as expected but the tableView scroll becomes jerky. And just for the information, I don't want to use any third party library.
Other Methods used for the class
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if (indexPath.row % 2) == 0 {
cell.backgroundColor = UIColor.gray
}else {
cell.backgroundColor = UIColor.white
}
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderViewCell") as! HeaderViewCell
return headerCell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 53.0
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateHeaderView()
}
}
i am trying to make space between cells in UItableview i've checked google all posts i found is more than 3 years old , when i try to apply them i am getting so many errors, is it possible to make space between cells in UItableview ?
my Code :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell") as! ImageCell
cell.model = self.modelAtIndexPath(indexPath)
let url = URL(string: cell.model.imageName)
cell.imgBack.kf.setImage(with: url)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//send back playlist count
if (section == 0) {
return self.lists_arr.count
}
return 0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated:true)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let imageCell = cell as! ImageCell
self.setCellImageOffset(imageCell, indexPath: indexPath)
}
//number of sections in table
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func modelAtIndexPath(_ indexPath: IndexPath) -> CellPlaylist {
return self.lists_arr[(indexPath as NSIndexPath).row % self.lists_arr.count]
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tblMain) {
for indexPath in self.tblMain.indexPathsForVisibleRows! {
if let imgCel : ImageCell = self.tblMain.cellForRow(at: indexPath) as? ImageCell {
self.setCellImageOffset(imgCel, indexPath: indexPath)
}
}
}
}
func setCellImageOffset(_ cell: ImageCell, indexPath: IndexPath) {
let cellFrame = self.tblMain.rectForRow(at: indexPath)
let cellFrameInTable = self.tblMain.convert(cellFrame, to:self.tblMain.superview)
let cellOffset = cellFrameInTable.origin.y + cellFrameInTable.size.height
let tableHeight = self.tblMain.bounds.size.height + cellFrameInTable.size.height
let cellOffsetFactor = cellOffset / tableHeight
cell.setBackgroundOffset(cellOffsetFactor)
}
The class of TableCell :
class ImageCell: UITableViewCell {
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var imgBack: UIImageView!
#IBOutlet weak var imgBackTopConstraint: NSLayoutConstraint!
#IBOutlet weak var imgBackBottomConstraint: NSLayoutConstraint!
let imageParallaxFactor: CGFloat = 70
var imgBackTopInitial: CGFloat!
var imgBackBottomInitial: CGFloat!
var model: CellPlaylist! {
didSet {
self.updateView()
}
}
override func awakeFromNib() {
self.clipsToBounds = true
self.imgBackBottomConstraint.constant -= 2 * imageParallaxFactor
self.imgBackTopInitial = self.imgBackTopConstraint.constant
self.imgBackBottomInitial = self.imgBackBottomConstraint.constant
}
func updateView() {
// self.imgBack.imageFromServerURL(urlString: self.model.imageName)
//self.getImage(url: self.model.imageName,imgView: self.imgBack)
//self.model.imageName
self.layer.cornerRadius = 10
self.layer.masksToBounds = true
self.layer.cornerRadius = 8
self.layer.shadowOffset = CGSize(width: 0, height: 3)
self.layer.shadowRadius = 3
self.layer.shadowOpacity = 0.3
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 8, height: 8)).cgPath
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
self.contentView.layoutMargins.top = 20
self.lblTitle.text = self.model.title
}
func setBackgroundOffset(_ offset:CGFloat) {
let boundOffset = max(0, min(1, offset))
let pixelOffset = (1-boundOffset)*2*imageParallaxFactor
self.imgBackTopConstraint.constant = self.imgBackTopInitial - pixelOffset
self.imgBackBottomConstraint.constant = self.imgBackBottomInitial + pixelOffset
}
}
The storyboard :
what i am getting
:
what i want :
Make Tablview BG colour white and set BG View colour in cell that you want to keep see in image i have set bgview BG colour is light greay and make BGview hight smaller then cell i mean if you want to set space 10 pixel keep Bg hight smaller then cell 10 pixel
Here is my cell
And here is out put
Update: UIEdgeInsetsInsetRect method is replaced now you can do it like this
contentView.frame = contentView.frame.inset(by: margins)
Swift 4 answer:
in your custom cell class add this function
override func layoutSubviews() {
super.layoutSubviews()
//set the values for top,left,bottom,right margins
let margins = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
contentView.frame = UIEdgeInsetsInsetRect(contentView.frame, margins)
}
You can change values as per your need
Swift 4.2 solution
Inside UITableViewCell subclass
override func layoutSubviews() {
super.layoutSubviews()
let padding = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
bounds = bounds.inset(by: padding)
}
Swift 5.0 solution
Inside UITableViewCell subclass
override func layoutSubviews() {
super.layoutSubviews()
let padding = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
bounds = UIEdgeInsetsInsetRect(bounds, padding)
}
You can let every cell to take a section in group tableView, then you set the section's footer.
Try my code:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.register(UINib.init(nibName: "VC1Cell", bundle: nil), forCellReuseIdentifier: "VC1Cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: -- tableview delegate
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let view:UIView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.bounds.size.width, height: 10))
view.backgroundColor = .clear
return view
}
func numberOfSections(in tableView: UITableView) -> Int {
return 10
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:VC1Cell = tableView.dequeueReusableCell(withIdentifier: "VC1Cell") as! VC1Cell
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 10.0
}
}
The result:
Building on Gulfam Khan's answer, the new way of setting the inset:
Swift 4:
override func layoutSubviews() {
super.layoutSubviews()
//set the values for top,left,bottom,right margins
let margins = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
contentView.frame = contentView.frame.inset(by: margins)
}
Swift 4:
override func layoutSubviews() {
super.layoutSubviews()
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0))
}
Swift 5.2 Solution
override func layoutSubviews() {
super.layoutSubviews()
let padding = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
bounds = bounds.inset(by: padding)
}