Show all cells in UITableView - ios

I have got this table in my swift project
tableView = UITableView()
tableView.dataSource = self
tableView.delegate = self
let tableViewHeight = postTexts.count*200
tableView.estimatedRowHeight = 55
tableView.rowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false;
tableView.reloadData()
tableView.layoutIfNeeded()
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
return 55
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let ProfilePicture = UIImageView()
ProfilePicture.image = #imageLiteral(resourceName: "cole")
let username = UILabel()
username.text = posters[indexPath.row]
username.numberOfLines = 0
let postText = UITextView()
postText.text = postTexts[indexPath.row]
postText.isScrollEnabled = false
postText.isUserInteractionEnabled = false
let border = UIView()
border.backgroundColor = UIColor(r: 17, g: 221, b: 219)
cell.addSubview(ProfilePicture)
cell.addSubview(username)
cell.addSubview(postText)
cell.addSubview(border)
ProfilePicture.anchor(cell.topAnchor, left:cell.leftAnchor, bottom: nil, right: nil, topConstant: 15, leftConstant: 14, bottomConstant: 0, rightConstant: 0, widthConstant: 50,heightConstant:50)
username.anchor(cell.topAnchor, left:ProfilePicture.rightAnchor, bottom: postText.topAnchor, right: cell.rightAnchor, topConstant: 20, leftConstant: 13, bottomConstant: 0, rightConstant: 15, widthConstant: 0)
postText.anchor(username.bottomAnchor, left:ProfilePicture.rightAnchor, bottom:nil, right: cell.rightAnchor, topConstant: 0, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0)
border.anchor(postText.bottomAnchor, left:cell.leftAnchor, bottom: cell.bottomAnchor, right: cell.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 20, rightConstant: 0, widthConstant: 0,heightConstant:1)
cell.layoutIfNeeded()
cell.sizeToFit()
return cell
}
I want my table to show all cells,but it only shows half of them like here
As you see he only shows 2 cells even though there are 4 of them,how can i change it's behaviour to show all cells?
Here are my table constraints
tableView.anchor(PostsDiv.bottomAnchor, left:view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 40, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0,heightConstant:tableView.contentSize.height+tableView.contentInset.bottom+tableView.contentInset.top)

This is still the same issue from your older posts. Your cells aren't working correctly since you want automatic height in cells but you have the wrong constraints set on your tableView and cell. This is a third repost of your question but here is your answer from Andrea and me:
Swift UITableViewAutomaticDimension is not working

I created nearly the same UI using interface builder.
https://github.com/Hapeki/Example4
I recommend you take a look at this and how AutoLayout works before settings stuff programmatically. The UI is based on my explanation from https://stackoverflow.com/a/42971009/6414904
Demo video:
The cells are automatically sized, seen by the large lorem ipsum text. If you want to make the entire screen scroll you should consider making a headerView for your tableView, but that's out of the scope for this question. In your code you set the tableView height based on the count of your cells * height: let tableViewHeight = postTexts.count*200
, thats is the wrong way to work and it will cause issues after issues. I would highly recommend using interface builder (Storyboards) or if you want some "hybrid" approach you could go for xibs/nibs, where you can make View classes that contain outlets and do some programmatic stuff in it.

Related

Why do ScrollViews not function in TableViewCells?

I have been building apps for half a decade and I have never been able to figure out how to get ScrollViews to work inside of TableViewCells when the cell height is automatically calculated (UITableView.automaticDimension) despite the scroll view inside the cell being properly configured.
Here is some code to get an idea of what I mean:
func configureViewComponents() {
view.addSubview(tableView)
tableView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 10, paddingLeft: 0, paddingBottom: 0, paddingRight: 0)
tableView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.allowsSelection = true
tableView.isUserInteractionEnabled = true
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.register(EventCell.self, forCellReuseIdentifier: "EventCell")
view.bringSubviewToFront(tableView)
}
Inside ScrollViewDelegate:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
ScrollView inside UITableViewCell ("line" is a view above the scroll view):
addSubview(mediaScroll)
mediaScroll.anchor(top: line.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: Concurrent.shared.deviceWidth, height: Concurrent.shared.deviceWidth)
ScrollViews will not function under these circumstances. However, if you replace "UITableView.automaticDimension" with an integer, suddenly they come back to life and function properly.
Does anyone in the community understand why?

Instruments show "_NSContiguousstring" memory leak when scrolling UITableView

I have a UItableView which consist of 10 element. I opened Instruments to catch the memory leaks and when I scroll tableView, It started to give memory leaks. In Instruments I tried to find which causes the leaks but can't figure out, It says "_NScontiguousstring" for whole leaks.
I found some solutions for Objective-C which they check If cell is nil in "CellForRowAt" function. I don't think it is useful for Swift but I tried and as expected It doesn't work.
Memory Leak UITableView
My question is what can cause this kind of memory leak?
Devices I test it;
iPhone X on 11.3.1
iPhone 6 11.2.5
Controller Class;
class TableViewController: UITableViewController {
let teamModel = TeamModel(uid: "adsada", name: "First Team ", idea: "idea 1", slogan: "Slogan 1", university: "dasda", image: "info", isActive: true)
let teamModel2 = TeamModel(uid: "adsada", name: "Team 2", idea: "idea 2", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel3 = TeamModel(uid: "adsada", name: "Team 3", idea: "idea 3", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel4 = TeamModel(uid: "adsada", name: "Team 4", idea: "idea 4", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel5 = TeamModel(uid: "adsada", name: "Team 5", idea: "idea 5", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel6 = TeamModel(uid: "adsada", name: "Team 6", idea: "idea 6", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel7 = TeamModel(uid: "adsada", name: "Team 7", idea: "idea 7", slogan: "adasd", university: "dasda", image: "info", isActive: true)
var data: [TeamModel] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(mainTableCell.self, forCellReuseIdentifier: "mainTableCell")
data = [teamModel,teamModel2,teamModel3,teamModel4,teamModel5,teamModel6,teamModel7]
}
// MARK: - Table view data source
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 data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mainTableCell", for: indexPath) as! mainTableCell
let cell_data = data[indexPath.row]
cell.cell_data = cell_data
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
}
Cell Class;
class mainTableCell: UITableViewCell{
var cell_data: TeamModel?{
didSet{
guard let unwrappedCell = cell_data else { return }
if let url = unwrappedCell.imageURL{
profileImage.image = UIImage(named: "info")
} else{
self.profileImage.image = UIImage(named: "info")
}
self.teamLbl.text = unwrappedCell.name
mainBackground.backgroundColor = UIColor.gray
}
}
let mainBackground: UIView = {
let v = UIView()
v.layer.cornerRadius = 8
v.layer.masksToBounds = true
return v
}()
var isVoteable: Bool = false
//let shadowView = ShadowView()
let profileImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.masksToBounds = true
return imageView
}()
let teamLbl: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
return label
}()
let myVoteLbl: UILabel = {
let l = UILabel()
l.text = "Oyum: --"
return l
}()
let voteBtn: UIButton = {
let b = UIButton(type: .custom)
b.setImage(UIImage(named: "info"), for: .normal)
return b
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
func setupViews() {
self.backgroundColor = UIColor.white
self.mainBackground.addSubview(profileImage)
self.mainBackground.addSubview(teamLbl)
self.mainBackground.addSubview(voteBtn)
self.mainBackground.addSubview(myVoteLbl)
//self.addSubview(shadowView)
self.addSubview(mainBackground)
self.backgroundColor = UIColor.clear
profileImage.translatesAutoresizingMaskIntoConstraints = false
teamLbl.translatesAutoresizingMaskIntoConstraints = false
voteBtn.translatesAutoresizingMaskIntoConstraints = false
myVoteLbl.translatesAutoresizingMaskIntoConstraints = false
mainBackground.translatesAutoresizingMaskIntoConstraints = false
//shadowView.translatesAutoresizingMaskIntoConstraints = false
}
override func layoutSubviews() {
super.layoutSubviews()
// self.setCircularImageView()
mainBackground.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// shadowView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: 0, heightConstant: 0)
profileImage.anchor(nil, left: self.mainBackground.leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 10, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 60)
profileImage.anchorCenterYToSuperview()
teamLbl.anchor(self.mainBackground.topAnchor, left: profileImage.rightAnchor, bottom: nil, right: self.voteBtn.leftAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)
myVoteLbl.anchor(nil, left: profileImage.rightAnchor, bottom: self.mainBackground.bottomAnchor, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
voteBtn.anchor(nil, left: nil, bottom: nil, right: self.mainBackground.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 80, heightConstant: 80)
voteBtn.anchorCenterYToSuperview()
}
func setCircularImageView() {
self.profileImage.layer.cornerRadius = CGFloat(roundf(Float(self.profileImage.frame.size.width / 2.0)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
EDIT: I add prepareForReuse method regarding to below answer but now cells show just white. Am I doing something wrong?
override func prepareForReuse() {
super.prepareForReuse()
teamLbl.text = ""
myVoteLbl.text = ""
profileImage.image = nil
}
I also make cell_data variable "weak var cell_data: TeamModel? and nil it in prepareForReuse() method but still same leaks are coming.
EDIT 2: Full project;
https://github.com/emreond/TableView-Memory-Leak-Project
EDIT 3: I found that when I add If check and change attributes inside didst of cell_data, some cells views look ruined. For example when I change teamLbl text color inside cell_data. In some cells, It looks ruined.
EDIT 4: When I comment anchor codes to check with reference of #Darp's answer,(I don't have anything seen on screen and don't have any constraint) It still continue to give leak.
EDIT 5: I'm still working on this leak but can't find any solution. Actually when I look what is in memory when tableView is on screen, I see that only 8 cell is on memory which looks like correct.
I have the same problem with _NSContiguousString. Even in an empty application with just one label, it shows a leak of 48 bytes.
I am not sure, but I have a guess that the reason for leaking might be bridging with NSString (I see also [_SwiftNativeNSStringBase retain] on the top of the stack trace).
I've found out that NSString itself might be considered as a leaking object by the Instruments because it has been implemented as a Singleton.
My own question is here: Memory leaks when assigning text to UILabel (iOS, Swift 4, XCode9)
First things first.
Inside layoutSubviews you are setting anchores. Why ? It's going to be called each time your cells will be called.
Instead of this, move
// self.setCircularImageView()
mainBackground.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// shadowView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: 0, heightConstant: 0)
profileImage.anchor(nil, left: self.mainBackground.leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 10, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 60)
profileImage.anchorCenterYToSuperview()
teamLbl.anchor(self.mainBackground.topAnchor, left: profileImage.rightAnchor, bottom: nil, right: self.voteBtn.leftAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)
myVoteLbl.anchor(nil, left: profileImage.rightAnchor, bottom: self.mainBackground.bottomAnchor, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
voteBtn.anchor(nil, left: nil, bottom: nil, right: self.mainBackground.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 80, heightConstant: 80)
voteBtn.anchorCenterYToSuperview()
Just bellow setupViews() call.
Next thing is that you didn't implement prepareForReuse(), you need to nil the values which u are setting in cellForRow, willDislayCell` etc.
EDIT
var cell_data: TeamModel? - Marking it as optional doesn't make it weak reference, mark it as weak var and nil it every time cell gets reused.

Inaccuracy addSubview in UICollectionViewCell

There was a big problem that I can not solve for a couple of days.
I have a UIViewController with UICollectionView in which there will be 3 cells with different content. Here is my class:
class PostView: AppViewAddMenu, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var homeController: FeedController?
var contentArray = [PostContentModel]()
var postInfo: PostModel?
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 3
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.delegate = self
cv.dataSource = self
cv.backgroundColor = .white
return cv
}()
override func setupViewController() {
collectionView.register(PostViewCell.self, forCellWithReuseIdentifier: "cellId")
view.addSubview(collectionView)
view.addConstraintsWithFormat("H:|[v0]|", views: collectionView)
view.addConstraintsWithFormat("V:|-60-[v0]|", views: collectionView)
fetchPost(id: postInfo?.id)
}
func fetchPost(id: Int?){
guard let ID = id else {
print("ID faild")
return
}
let url: String = "https://FTP.ru/wp-json/mobileApi/v1/post/\(ID)"
ApiService.sharedInstance.fetchContent(url: url, completion: { (Posts: [PostContentModel]) in
self.contentArray = Posts
self.collectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! PostViewCell
cell.contentArray = contentArray
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 1000)
}
}
The idea of the first cell is to take json from a site that looks like this: [switch, content]. From the switch value in UICollectionViewCell, different functions are called, which add an element in UICollectionViewCell via addSubview (). Here's the code:
class PostViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
anchor = self.topAnchor
}
var anchor: NSLayoutYAxisAnchor?
var contentArray: [PostContentModel]?{
didSet{
for number in contentArray! {
if(number.switcher == 1) {
anchor = addTextContent(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 2){
anchor = addImageContent(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 3){
anchor = addCaptionFirst(content: number.content!, bottomAnchor: anchor!)
}
if(number.switcher == 4){
anchor = addButtonLink(content: number.content!, link: number.link!, bottomAnchor: anchor!)
}
}
}
}
func addTextContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor{
let shortContentPost: UILabel = {
let label = UILabel()
label.text = content
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular)
return label
}()
addSubview(shortContentPost)
shortContentPost.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return shortContentPost.bottomAnchor
}
func addImageContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let image: CustomImageView = {
let image = CustomImageView()
image.image = UIImage(named: content)
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
return image
}()
let imageURL = "https://brodude.ru/wp-content/uploads/" + content.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
image.loadImageUsingUrlString(urlString: imageURL)
addSubview(image)
image.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 250)
return image.bottomAnchor
}
func addCaptionFirst(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let Caption: UILabel = {
let lb = UILabel()
lb.text = content
lb.numberOfLines = 0
lb.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.semibold)
return lb
}()
addSubview(Caption)
Caption.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 30, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return Caption.bottomAnchor
}
func addButtonLink(content: String, link: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
let button: LinkButton = {
let bt = LinkButton()
bt.LinkString = link
bt.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.semibold)
bt.setTitle(content, for: UIControlState.normal)
bt.sizeToFit()
bt.titleLabel?.numberOfLines = 0
bt.contentHorizontalAlignment = .left
bt.setTitleColor(UIColor(red: 0.07, green: 0.32, blue: 0.89, alpha: 1.0), for: UIControlState.normal)
bt.addTarget(self, action: #selector(linkOut), for: .touchUpInside)
return bt
}()
addSubview(button)
button.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 20, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
return button.bottomAnchor
}
The algorithm works satisfactorily, but the problem begins when the cell is updated. When scrolling, with collectionView.reloadData (). New subview layered on the past, the text becomes fatter and clogged device memory. The process continues indefinitely until it gives an error.
Example of a problem:, ,
Sorry for my English.
First of all, instead of:
addSubview(shortContentPost)
use:
contentView.addSubview(shortContentPost)
Do this for all the subviews that you add. contentView is supposed to hold your content.
Implement this prepareForReuse in your cell:
override func prepareForReuse() {
super.prepareForReuse()
let subviews = contentView.subviews
for subview in subviews {
subview.removeFromSuperview()
}
}
This will clean your cell's content before reusing the cell.
Although I would STRONGLY recommend NOT to add/remove those subviews dynamically, because then you lose much of the reuse mechanism. I would add all the views (labels/imageViews) to the cell by default, and then use their isHidden property to hide/unhide them based on the content (e.g., if an image should be show, set the isHidden to true on all the others). This would be performance-wise better for reusing, because then the UI objects will not have to be recreated everytime a cell is reused, you would just reconfigure the content of the labels/imageViews.

how to edit tableViewCell when Tableview is in editing mode

I'm making a App like whatsApp Please check whatsApp calls tab. When we click we click on edit how I should move cell towards left when tableview is in editing mode. Please ignore the Ancher function I created a separate function to handle anchoring . ScreenShot 1 ScreenShot 2
import UIKit
class CallsTabController: UITableViewController {
let id = "reuseIdentifier"
var arr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(cell.self, forCellReuseIdentifier: id)
arr = ["Sachin","Papa","Mummy","Sachin","Papa","Mummy","Sachin","Papa","Mummy"]
setupNav()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell1 = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)as! cell
cell1.data = arr[indexPath.row]
return cell1
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
arr.remove(at: indexPath.row)
print("Delete")
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath){
cell.separatorInset = UIEdgeInsetsMake(0, 30, 0, 0)
tableView.separatorInset = UIEdgeInsetsMake(0, 30, 0, 0)
}
//
func add() {
}
func EditAction() {
tableView.isEditing = !tableView.isEditing
if tableView.isEditing == true {
self.navigationItem.leftBarButtonItem?.title = "done"
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "clear", style: .plain, target: self, action:#selector(self.EditAction))
}
else {
self.navigationItem.leftBarButtonItem?.title = "Edit"
let button1 = UIBarButtonItem(image: #imageLiteral(resourceName: "Calls"), style: .plain, target: self, action: #selector(self.add))
self.navigationItem.rightBarButtonItem = button1
}
}
func setupNav(){
let button1 = UIBarButtonItem(image: #imageLiteral(resourceName: "Calls"), style: .plain, target: self, action: #selector(self.add))
self.navigationItem.rightBarButtonItem = button1
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Edit", style: .plain, target: self, action:#selector(self.EditAction))
self.navigationItem.titleView = {
let search = UISegmentedControl(items: ["All","Missed"])
search.apportionsSegmentWidthsByContent = false
search.selectedSegmentIndex = 0
return search
}()
self.tableView.addSubview(UISearchBar())
}
}
class cell : UITableViewCell {
let frameview = { () -> UIView in
let view = UIView()
return view
}()
var Name = { () -> UILabel in
let lab = UILabel()
lab.font = UIFont(name: "HelveticaNeue-Light", size: 16.0)
lab.textColor = UIColor.black
return lab
}()
var Description = { () -> UILabel in
let lab = UILabel()
lab.font = UIFont(name: "helveticaNeue-UltraLight", size: 12.0)
lab.textColor = UIColor.black
return lab
}()
var TimeLabel = { () -> UILabel in
let lab = UILabel()
lab.textAlignment = .right
lab.font = UIFont(name: "helveticaNeue-light", size: 12.0)
lab.textColor = UIColor.gray
lab.text = "yesterday"
return lab
}()
var infoBtn:UIButton = { () -> UIButton in
let btn = UIButton()
btn.setImage(#imageLiteral(resourceName: "info"), for: .normal)
return btn
}()
var Calltype:UIImageView = { () -> UIImageView in
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.image = #imageLiteral(resourceName: "Recivecall")
return imageView
}()
var data:String? {
didSet {
Name.text = self.data
Description.text = "home"
}
}
var frameLeftAncherValue:CGFloat?{
didSet {
Ancher()
}
}
var frameRightAncherValue = 0
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
Setup()
Ancher()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func Setup() {
addSubview(frameview)
addSubview(Calltype)
addSubview(Name)
addSubview(Description)
addSubview(infoBtn)
addSubview(TimeLabel)
}
func Ancher() {
Calltype.anchor(frameview.topAnchor, left: frameview.leftAnchor, bottom: frameview.bottomAnchor, right: nil, topConstant: 8, leftConstant: 8, bottomConstant: 8, rightConstant: 0, widthConstant: 20.0, heightConstant: 0)
infoBtn.anchor(nil, left: nil, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 16.0, widthConstant: 20.0, heightConstant: 20.0)
infoBtn.anchorCenterYToSuperview()
Description.anchor(nil, left: Calltype.rightAnchor, bottom: frameview.bottomAnchor, right: infoBtn.leftAnchor, topConstant: 1, leftConstant: 4, bottomConstant: 4, rightConstant: 4, widthConstant: 0, heightConstant: 0)
Name.anchor(frameview.topAnchor, left: Calltype.rightAnchor, bottom: nil, right: infoBtn.leftAnchor, topConstant: 2, leftConstant: 4, bottomConstant: 0, rightConstant: 4, widthConstant: 0, heightConstant: 0)
TimeLabel.anchor(nil, left: nil, bottom: nil, right: infoBtn.leftAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 8, widthConstant: 0, heightConstant: 0)
TimeLabel.anchorCenterYToSuperview()
frameview.anchor(topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: 0, leftConstant: frameLeftAncherValue ??
0.0, bottomConstant: 0, rightConstant: CGFloat(frameRightAncherValue), widthConstant: 0, heightConstant: 0)
}
}
Your image looks as if you have added sub views to the cells view property and not the contentView property. In order for the content to re-size during editing, you must add new UIViews to the contentView property.
Example:
func setupViews() {
self.contentView.addSubview(frameview)
self.contentView.addSubview(Calltype)
self.contentView.addSubview(Name)
self.contentView.addSubview(Description)
self.contentView.addSubview(infoBtn)
self.contentView.addSubview(TimeLabel)
}

iOS/Swift: issues with UITableViewCell height

I wrote a UITableView that has custom UITableViewCell, and the data loading and the table data population has no problem, but the Cell height is so wrong that the content of each cell is only half visible (see the attached screenshots)
I have a .xib file (as show in the second screenshot above) for the UITableViewCell and have written a class that overrides the UITableViewCell class with the layoutSubviews() implementation below, in which I used the [Neon][3] library to do the positioning/layout of the UI elements:
override func layoutSubviews() {
super.layoutSubviews()
self.contentView.clipsToBounds = true
avatarImage.anchorInCorner(.TopLeft, xPad: 2, yPad: 2, width: 15, height: 15)
postedByUsername.align(.ToTheRightCentered, relativeTo: avatarImage, padding: 1, width: 190, height: 15)
timeAgo.anchorInCorner(.TopRight, xPad: 2, yPad: 2, width: 130, height: 15)
questionTitle.alignAndFill(align: .UnderMatchingLeft, relativeTo: avatarImage, padding: 3)
firstAttachedImage.align(.ToTheRightMatchingTop, relativeTo: questionTitle, padding: 3, width: 40, height: 40)
self.answerButton.setFAText(prefixText: "", icon: FAType.FAReply, postfixText: "2", size: 14, forState: .Normal)
self.commentButton.setFAText(prefixText: "", icon: FAType.FACommentO, postfixText: "1", size: 14, forState: .Normal)
self.likeButton.setFAText(prefixText: "", icon: FAType.FAHeartO, postfixText: "10", size: 14, forState: .Normal)
answerCommentLikeStackView.align(.UnderMatchingLeft, relativeTo: questionTitle, padding: 3, width: 190, height: 30)
self.setNeedsUpdateConstraints()
}
In my UITableViewController implementation, I set the cell/row height like below:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 150
self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
// disable horizontal scroll
self.tableView.contentSize = CGSizeMake(self.tableView.frame.size.width, self.tableView.contentSize.height)
But the cell height is still wrong, what else can I do to make the height look right?
Instead of setting tableView.rowHeight = x, try overriding the heightForRowAtIndexPath method instead:
override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
This should get called for every cell the table view renders and resize it accordingly.
I like using the cellForRowAtIndexPath function. This way your rowHeight gets set in the same function that fills up the table with data:
//Fills up the tableview with data
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("YourCell", forIndexPath: indexPath) as! YourCell
//This is where the magic is happening
tableView.rowHeight = 75;
return cell
}

Resources