How to center a textView in a tableViewCell? - ios

I have a static tableView that I am creating like so....
override func viewDidLoad() {
super.viewDidLoad()
usernameLabel.text = "Username"
usernameDisplay.text = "placeholder"
usernameDisplay.textColor = self.view.tintColor
usernameLabel.frame = CGRect(x: self.view.bounds.minX, y: self.usernameCell.bounds.minY, width: self.view.frame.width, height: self.usernameCell.bounds.height)
usernameDisplay.frame = CGRect(x: self.usernameCell.bounds.minX, y: self.usernameCell.bounds.minY, width: self.view.frame.width, height: self.usernameCell.bounds.height)
usernameDisplay.textAlignment = .right
usernameCell.addSubview(usernameLabel)
usernameCell.addSubview(usernameDisplay)
membershipTierLabel.text = "Membership Status"
membershipTierDisplay.text = "Free (0-1GB)"
membershipTierDisplay.textColor = self.view.tintColor
membershipTierLabel.frame = CGRect(x: self.view.bounds.minX, y: self.membershipTierCell.bounds.minY, width: self.view.frame.width, height: self.membershipTierCell.bounds.height)
membershipTierDisplay.frame = CGRect(x: self.view.bounds.minX, y: self.membershipTierCell.bounds.minY, width: self.view.frame.width, height: self.membershipTierCell.bounds.height)
membershipTierDisplay.textAlignment = .right
membershipTierCell.addSubview(membershipTierLabel)
membershipTierCell.addSubview(membershipTierDisplay)
dataUsedLabel.text = "Data Used"
dataUsedDisplay.text = String(UserDefaults.standard.integer(forKey: "total_storage"))
dataUsedDisplay.textColor = self.view.tintColor
dataUsedLabel.frame = CGRect(x: self.view.bounds.minX, y: self.dataUsedCell.bounds.minY, width: self.view.frame.width, height: self.dataUsedCell.bounds.height)
dataUsedDisplay.frame = CGRect(x: self.view.bounds.minX, y: self.membershipTierCell.bounds.minY, width: self.view.frame.width, height: self.membershipTierCell.bounds.height)
dataUsedDisplay.textAlignment = .right
dataUsedCell.addSubview(dataUsedLabel)
dataUsedCell.addSubview(dataUsedDisplay)
tipsText.text = "You can change the color of a progression tag by long-pressing it on the Progressions homepage"
tipsText.frame = CGRect(x: tipsCell.bounds.minX,y: self.tipsCell.bounds.minY,width: tipsCell.bounds.width,height:self.tipsCell.bounds.height)
//tipsText.textColor = UIColor.white
//tipsText.textAlignment = .center
tipsText.backgroundColor = self.view.tintColor
tipsText.font = tipsText.font?.withSize(15)
tipsText.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tipsText.centerYAnchor.constraint(equalTo: tipsCell.centerYAnchor, constant:0).isActive = true
// tipsText.centerXAnchor.constraint(equalTo: tipsCell.centerXAnchor, constant:0).isActive = true
//tipsText.textContainerInset = UIEdgeInsets(top: 10, left: 5, bottom: 10, right: 5)
tipsCell.backgroundColor = self.view.tintColor
tipsCell.addSubview(tipsText)
tipsText.center = CGPoint(x: tipsCell.bounds.midX, y: tipsCell.bounds.midY)
feedbackText.text = "Feedback is loved! Please email with any issues, comments, ideas, or concerns"
feedbackText.frame = CGRect(x: self.feedbackCell.bounds.minX,y: self.feedbackCell.bounds.minY,width: self.feedbackCell.bounds.width,height:self.feedbackCell.bounds.height)
feedbackText.font = feedbackText.font?.withSize(15)
feedbackCell.addSubview(feedbackText)
//let bytes = UserDefaults.standard.integer(forKey: "total_storage")
//storageAmount.text = format(bytes:Double(bytes))
// Do any additional setup after loading the view.
//myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section != 0 {
return 100
} else {
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch(section) {
case 0: return 3 // section 0 has 2 rows
case 1: return 1
case 2: return 1// section 1 has 1 row
default: fatalError("Unknown number of sections")
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch(indexPath.section) {
case 0:
switch(indexPath.row){
case 0:
print("username")
return self.usernameCell
case 1:
return self.membershipTierCell
case 2:
return self.dataUsedCell
default: fatalError("Unknown row")
}
case 1:
switch(indexPath.row){
case 0:
return self.tipsCell
default: fatalError("Unknown row")
}
case 2:
print("feedback")
switch(indexPath.row){
case 0:
print("feedback")
return self.feedbackCell
default: fatalError("Unknown row")
}
default: fatalError("Unknown section")
}
}
}
Right now it looks like
As you can see I am trying to set the tipsText (UITextView) in the exact center of the tipsCell using: tipsText.center = CGPoint(x: tipsCell.bounds.midX, y: tipsCell.bounds.midY)
As you can see, this isn't working as the tipsText is still on the top of the tipsCell. How can I center it like I want here?

I think you have two ways to fulfill your wish.
One way is to set the heights of tipsCell and feedBackCell to 100 in IB if you have.
The other way is to add the codes as the following:
tipsText.textAlignment = .center
tipsText.numberOfLines = 0
tipsText.autoresizingMask = [.flexibleWidth, .flexibleHeight]
feedbackText.textAlignment = .center
feedbackText.numberOfLines = 0
feedbackText.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Hopefully it is helpful.
If it is TextView, you may get estimated frames like this:
tipsText.textContainer.maximumNumberOfLines = 0
tipsText.textContainer.heightTracksTextView = true
tipsText.attributedText = NSAttributedString.init(string: "You can change the color of a progression tag by long-pressing it on the Progressions", attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15) ])
tipsText.textAlignment = .center
let size = tipsText.textContainer.size
tipsText.frame = CGRect(x: tipsCell.bounds.minX,y: self.tipsCell.bounds.minY,width: tipsCell.bounds.width, height :size.height )
tipsText.backgroundColor = self.view.tintColor
tipsText.autoresizingMask = [.flexibleWidth, .flexibleHeight]
tipsCell.backgroundColor = self.view.tintColor
tipsCell.addSubview(tipsText)
tipsText.center = CGPoint(x: tipsCell.bounds.midX, y: tipsCell.bounds.midY)
feedbackText.textContainer.maximumNumberOfLines = 0
feedbackText.textContainer.heightTracksTextView = true
feedbackText.attributedText = NSAttributedString.init(string: "Feedback is loved! Please email with any issues, comments, ideas, or concerns", attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15) ])
feedbackText.textAlignment = .justified
let feedbackSize = feedbackText.textContainer.size
feedbackText.frame = CGRect(x: feedbackCell.bounds.minX,y: self.feedbackCell.bounds.minY,width: feedbackCell.bounds.width, height :feedbackSize.height )
feedbackText.backgroundColor = self.view.tintColor
feedbackText.autoresizingMask = [.flexibleWidth, .flexibleHeight]
feedbackCell.backgroundColor = self.view.tintColor
feedbackCell.addSubview(feedbackText)
feedbackText.center = CGPoint(x: feedbackCell.bounds.midX, y: feedbackCell.bounds.midY)

I assume you know how to use custom view classes.
There a custom class for UITextView;
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}

Related

Swift Animation behaves weird after changing Label

I am currently working on an animation for my ios application. When it gets triggered three blocks (UIView with borders) move down and a new block comes in from the left.
It works perfectly until I change the text of the label (Block Number) before the animation starts. The blocks spawn in completely different positions and move back to the start position. They also change their order.
The following code shows my block class. For the animation I use the getBlockView and "view.frame = GCRect(...)". For changing the label text I use the setBlockName(number: String) function.
At the moment I don´t have any idea what could cause that and would be thankful for every suggestion what could cause this weird behaviour.
class myBlock {
var positionID: Int
var blockNumber: String
let blockView: UIView
let blockNumberLabel: UILabel
init(blockNumber: String, heightScreen: CGFloat, widthScreen: CGFloat, positionID: Int) {
self.positionID = positionID
self.blockNumber = blockNumber
blockView = {
let view = UIView()
view.autoSetDimension(.height, toSize: heightScreen / 6)
view.autoSetDimension(.width, toSize: widthScreen - 80)
view.layer.borderWidth = 3
view.layer.borderColor = UIColor.MyTheme.primaryColor1.cgColor
return view
}()
blockNumberLabel = {
let label = UILabel()
label.textColor = UIColor.MyTheme.primaryColor1
label.font = UIFont(name: "ArialMT", size: 20)
label.numberOfLines = 2
label.textAlignment = .left
label.adjustsFontForContentSizeCategory = true
label.text = "Block Number: \(blockNumber)"
label.isUserInteractionEnabled = false
return label
}()
blockView.addSubview(blockNumberLabel)
blockNumberLabel.autoPinEdge(toSuperviewEdge: .top, withInset: 5.0)
blockNumberLabel.autoPinEdge(toSuperviewEdge: .left, withInset: 5.0)
blockNumberLabel.autoPinEdge(toSuperviewEdge: .right, withInset: 5.0)
}
func getBlockView() -> UIView{
return blockView
}
func setBlockName(number: String) {
self.blockNumberLabel.text = "Block Number: \(number)"
}
func getBlockLabel() -> UILabel{
return blockNumberLabel
}
func getID() -> Int {
return positionID
}
func setID(id: Int) {
self.positionID = id
print("\(blockNumberLabel.text!): \(id)")
}
}
Animation Code:
private func moveBlocksDown(blockNumber: String) {
var resetBlock: UIView!
let animationHeight = (self.heightScreen / 6) + (self.blockDistance)
UIView.animate(withDuration: 2.0, animations: {
for var block in self.blockList {
let id = block.getID()
let blockView = block.getBlockView()
if block.getID() == 0 {
block.setBlockName(number: blockNumber)
}
print(id)
switch id {
case 0:
blockView.frame = CGRect(x: self.topX, y: self.topY, width: blockView.frame.width, height: blockView.frame.height)
print(block.getBlockLabel().text!)
case 1:
blockView.frame = CGRect(x: self.topX, y: self.middleY, width: blockView.frame.width, height: blockView.frame.height)
print(block.getBlockLabel().text!)
case 2:
blockView.frame = CGRect(x: self.topX, y: self.bottomY, width: blockView.frame.width, height: blockView.frame.height)
print(block.getBlockLabel().text!)
case 3:
blockView.frame = CGRect(x: self.topX, y: (self.bottomY + animationHeight), width: blockView.frame.width, height: blockView.frame.height)
print(block.getBlockLabel().text!)
resetBlock = blockView
default:
print("Unknown ID")
}
print("NewID \((id + 1) % 4)")
block.setID(id: (id + 1) % 4)
}
}, completion: { finish in
resetBlock.frame = CGRect(x: self.newX, y: self.newY, width: resetBlock.frame.width, height: resetBlock.frame.height)
})
}

UITableView skipping every other cell when populating labels swift

I'm trying to create several UITableViews programmatically in the same scroll view. I'm correctly loading the tables' data into each array, but for some reason the table is populating every other cell. I added a print statement in cellForRowAt: to make sure it wasn't skipping data somehow and it doesn't seem to.
Also, didSelectRowAt: isn't being called when I click on a row, but didHighlightRowAt: is called correctly. And using that the table cells seem to load properly, it's just skipping every other cell when populating them.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cellIdentifier = ""
switch tableView {
case tableView1:
cellIdentifier = "AddOnTableViewCell1"
case tableView2:
cellIdentifier = "AddOnTableViewCell2"
case tableView3:
cellIdentifier = "AddOnTableViewCell3"
case tableView4:
cellIdentifier = "AddOnTableViewCell4"
default:
print("Too many tables")
}
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? AddOnTableViewCell else {
fatalError("Dequed cell error")
}
let titleLabel = UILabel(frame: CGRect(x: 16, y: cell.frame.minY + 10, width: view.frame.width - 30, height: 30))
titleLabel.textColor = .black
titleLabel.textAlignment = .left
switch tableView {
case tableView1:
titleLabel.text = addOnContents1[indexPath.row]
print("\(indexPath.row), \(addOnContents1[indexPath.row])")
case tableView2:
titleLabel.text = addOnContents2[indexPath.row]
print("\(indexPath.row), \(addOnContents2[indexPath.row])")
case tableView3:
titleLabel.text = addOnContents3[indexPath.row]
print("\(indexPath.row), \(addOnContents3[indexPath.row])")
case tableView4:
titleLabel.text = addOnContents4[indexPath.row]
print("\(indexPath.row), \(addOnContents4[indexPath.row])")
default:
print("Too many tables")
}
cell.addSubview(titleLabel)
return cell
}
The print statements above show that the data added correctly corresponds to the indexRow.path, i.e. 0 is item00, 1 is item01, 2 is item02, 3 is item03, ...
Then here are the other two methods mentioned.
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
switch tableView {
case tableView1:
print(addOnContents1[indexPath.row])
case tableView2:
print(addOnContents2[indexPath.row])
case tableView3:
print(addOnContents3[indexPath.row])
case tableView4:
print(addOnContents4[indexPath.row])
default:
print("Too many tables")
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Pressed")
switch tableView {
case tableView1:
print(indexPath.row)
case tableView2:
print(indexPath.row)
case tableView3:
print(indexPath.row)
case tableView4:
print(indexPath.row)
default:
print("Too many tables")
}
}
Finally, here's my code for setting up the tableViews
func loadAddOnViews() {
var count = 1
for item in addOns {
var contentSize: CGFloat = 0
switch count {
case 1:
let label = UILabel(frame: CGRect(x: 16, y: yCoordinateForNewContent, width: scrollView.frame.width - 32, height: 50))
label.text = addOns[0].title
yCoordinateForNewContent += 50
scrollView.addSubview(label)
contentSize = CGFloat(addOnContents1.count)
print("content size: \(contentSize)")
contentSize = contentSize * cellSize
tableView1 = UITableView(frame: CGRect(x: 0, y: yCoordinateForNewContent, width: scrollView.frame.width, height: contentSize))
scrollView.addSubview(tableView1)
tableView1.delegate = self
tableView1.dataSource = self
self.tableView1.register(AddOnTableViewCell.self, forCellReuseIdentifier: "AddOnTableViewCell1")
yCoordinateForNewContent += contentSize + 20
tableView1.reloadData()
case 2:
let label = UILabel(frame: CGRect(x: 16, y: yCoordinateForNewContent, width: scrollView.frame.width - 32, height: 50))
label.text = addOns[1].title
yCoordinateForNewContent += 50
scrollView.addSubview(label)
contentSize = CGFloat(addOnContents2.count)
print("content size: \(contentSize)")
contentSize = contentSize * cellSize
tableView2 = UITableView(frame: CGRect(x: 0, y: yCoordinateForNewContent, width: scrollView.frame.width, height: contentSize))
scrollView.addSubview(tableView2)
tableView2.delegate = self
tableView2.dataSource = self
self.tableView2.register(AddOnTableViewCell.self, forCellReuseIdentifier: "AddOnTableViewCell2")
yCoordinateForNewContent += contentSize + 20
tableView2.reloadData()
case 3:
let label = UILabel(frame: CGRect(x: 16, y: yCoordinateForNewContent, width: scrollView.frame.width - 32, height: 50))
label.text = addOns[2].title
yCoordinateForNewContent += 50
scrollView.addSubview(label)
contentSize = CGFloat(addOnContents3.count)
print("content size: \(contentSize)")
contentSize = contentSize * cellSize
tableView3 = UITableView(frame: CGRect(x: 0, y: yCoordinateForNewContent, width: scrollView.frame.width, height: contentSize))
scrollView.addSubview(tableView3)
tableView3.delegate = self
tableView3.dataSource = self
self.tableView3.register(AddOnTableViewCell.self, forCellReuseIdentifier: "AddOnTableViewCell3")
yCoordinateForNewContent += contentSize + 20
tableView3.reloadData()
case 4:
let label = UILabel(frame: CGRect(x: 16, y: yCoordinateForNewContent, width: scrollView.frame.width - 32, height: 50))
label.text = addOns[3].title
yCoordinateForNewContent += 50
scrollView.addSubview(label)
contentSize = CGFloat(addOnContents4.count)
print("content size: \(contentSize)")
contentSize = contentSize * cellSize
tableView4 = UITableView(frame: CGRect(x: 0, y: yCoordinateForNewContent, width: scrollView.frame.width, height: contentSize))
scrollView.addSubview(tableView4)
tableView4.delegate = self
tableView4.dataSource = self
self.tableView4.register(AddOnTableViewCell.self, forCellReuseIdentifier: "AddOnTableViewCell4")
yCoordinateForNewContent += contentSize + 20
tableView4.reloadData()
default:
print("too many tables")
}
count += 1
}
}
And here's the screen with example data:
SimulatorScreen
Any help is greatly appreciated!
Thanks #Naresh for bringing my attention to this. I had declared the label in the AddOnTableViewCell class, but I was creating a label in the cellForRowAt: method, which I was adding as a subview to the cell. I simplified the tables to a single table with an array of arrays to hold the data. I made the following change to my AddOnTableViewCell class:
class AddOnTableViewCell: UITableViewCell {
var titleLabel: UILabel!
init(frame: CGRect, title:String) {
super.init(style: .default, reuseIdentifier: "AddOnTableViewCell")
titleLabel = UILabel(frame: CGRect(x: 16 , y: self.frame.minY + 10, width: self.frame.width - 32, height: 40))
titleLabel.textColor = UIColor.black
titleLabel.text = title
addSubview(titleLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}}
and I simplified my cellForRowAt: method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let title = tableContents[indexPath.section][indexPath.row]
let cell = AddOnTableViewCell(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: cellSize), title: title)
return cell
}
Thanks!

UITableViewCell gets reused and shows wrong drawing in UIView

I've been having this problem for weeks and I think I am not able to solve it.
I have a tableView which has custom tableViewCells and they are filled with data. The tableViewCell has two UILabels and one UIView.
The problem appears when I scroll several times the drawings on the UIViews are overlapped one with another, I think they are redrawn. I know that this behavior is because of the reuse of the cells but I can't even locate the origin of the problem.
UIViews show perfectly when opening the app
UIViews get overlapped after scrolling
My UITableView's cellForRowAtIndexPath is:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
let cell: CustomTableViewcell = self.tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath) as! CustomTableViewcell
//self.tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as! CustomTableViewcell
cell.prepareForReuse()
self.createUIForCell(cell)
self.configureCell(cell, indexPath: indexPath)
print("\t\(parsedData[indexPath.row].stationName): \(parsedData[indexPath.row].freeBikes)")
return cell
}
func createUIForCell(cell: CustomTableViewcell) {
cell.distanceLabel.textColor = UIColor.whiteColor()
cell.distanceLabel.backgroundColor = UIColor.clearColor()
cell.bikeStationLabel.textColor = UIColor.whiteColor()
cell.bikeStationLabel.backgroundColor = UIColor.clearColor()
}
func configureCell(cell: CustomTableViewcell, indexPath: NSIndexPath) {
let stations = parsedData[indexPath.row]
if indexPath.row % 2 == 0 {
cell.stackView.arrangedSubviews.first!.backgroundColor = cellBackgroundColor1
cell.progressView.backgroundColor = cellBackgroundColor2
} else {
cell.stackView.arrangedSubviews.first!.backgroundColor = cellBackgroundColor2
cell.progressView.backgroundColor = cellBackgroundColor1
}
cell.progressView.getWidth(stations.freeBikes, freeDocks: stations.freeDocks)
cell.getLocation(stations.latitude, longitude: stations.longitude)
cell.getParameters(stations.freeBikes, freeDocks: stations.freeDocks)
cell.bikeStationLabel.text = stations.stationName
if stations.distanceToLocation != nil {
if stations.distanceToLocation! < 1000 {
cell.distanceLabel.text = String(format: "%.f m", stations.distanceToLocation!)
} else {
cell.distanceLabel.text = String(format: "%.1f km", stations.distanceToLocation! / 1000)
}
} else {
cell.distanceLabel.text = ""
}
}
For the before mentioned UIVIew inside my custom cell I have created a separated class for it to handle the drawing and it looks like this:
import UIKit
class ProgressViewBar: UIView {
var freeBikes = 0
var freeDocks = 0
var text: UILabel? = nil
var text2: UILabel? = nil
func getWidth(freeBikes: Int, freeDocks: Int) {
self.freeBikes = freeBikes
self.freeDocks = freeDocks
}
override func drawRect(rect: CGRect) {
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: rect.width * (CGFloat(freeBikes) / (CGFloat(freeBikes) + CGFloat(freeDocks))), height: frame.height), cornerRadius: 0)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.CGPath
shapeLayer.strokeColor = UIColor.whiteColor().CGColor
shapeLayer.fillColor = UIColor.whiteColor().CGColor
self.layer.addSublayer(shapeLayer)
drawText(rect)
}
func drawText(rect: CGRect) {
if freeBikes != 0 {
text?.removeFromSuperview()
text = UILabel(frame: CGRect(x: 2, y: 0, width: 20, height: 20))
text!.text = String("\(freeBikes)")
text!.textAlignment = NSTextAlignment.Left
text!.font = UIFont(name: "HelveticaNeue-Thin", size: 17)
text!.backgroundColor = UIColor.clearColor()
text!.textColor = UIColor(red: 1/255, green: 87/255, blue: 155/255, alpha: 1)
self.addSubview(text!)
}
text2?.removeFromSuperview()
text2 = UILabel(frame: CGRect(x: rect.width * (CGFloat(freeBikes) / (CGFloat(freeBikes) + CGFloat(freeDocks))) + 2, y: 0, width: 20, height: 20))
text2!.text = String("\(freeDocks)")
text2!.textAlignment = NSTextAlignment.Left
text2!.font = UIFont(name: "HelveticaNeue-Thin", size: 17)
text2!.backgroundColor = UIColor.clearColor()
text2!.textColor = UIColor.whiteColor()
self.addSubview(text2!)
}
}
The view needs two parameters to be drawn and I pass them using the func getWidth(freeBikes: Int, freeDocks: Int) method calling it from the `ViewController. If any other piece of code is needed you can look at the repo.
The problem is that when reusing the cell you call drawRect once again and don't clear the already drawn rect. Clear it before drawing another one.

How do i position my footerView so that it is on the bottom of the UITableView?

I want the footerView to be displayed on the bottom of the screen. How do i make it so that the footerView is located at the bottom and when it is tapped, the key board is appeared? Any help would be appreciated. Thanks!
protocol CommentsTableViewControllerDelegate: class {
func pop()
func reloadComments()
}
class CommentsTableViewController: UITableViewController, UITextViewDelegate, UITableViewDataSource{
weak var delegate: CommentsTableViewControllerDelegate?
var commentView: UITextView?
var footerView: UIView?
var contentHeight: CGFloat = 0
var comments: [String]?
var postObject: PFObject! {
didSet {
println(postObject)
}
}
private var myComments: [PFObject]? {
didSet {
tableView.reloadData()
}
}
private var header_label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = UIRectEdge.None
println(postObject?.objectForKey("comments"))
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handlePostingComment:", name: postCommentNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleComments:", name: queryCommentNotification, object: nil)
// Query for comments
Downloader.sharedDownloader.queryForComments(postObject)
header_label = UILabel(frame: .zeroRect)
header_label.text = postObject["post"] as? String
header_label.sizeToFit()
header_label.frame.origin = .zeroPoint
tableView.tableHeaderView = header_label
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
/* Setup the datasource delegate */
tableView.delegate = self
tableView.dataSource = self
/* Setup the keyboard notifications */
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
/* Setup the contentInsets */
self.tableView.contentInset = UIEdgeInsetsZero
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
self.edgesForExtendedLayout = UIRectEdge.None
/* Make sure the content doesn't go below tabbar/navbar */
self.extendedLayoutIncludesOpaqueBars = true
self.automaticallyAdjustsScrollViewInsets = false
if(postObject?.objectForKey("comments") != nil) {
comments = postObject?.objectForKey("comments") as? [String]
}
println(postObject)
println(postObject?.objectForKey("text"))
}
func handleComments(notification: NSNotification) {
let comments = notification.object as? [PFObject]
if let comments = comments {
myComments = comments
}
}
func handlePostingComment(notification: NSNotification) {
if let success = notification.object as? Bool {
if success {
delegate?.reloadComments()
} else {
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return myComments?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
if let myComments = myComments {
let comment = myComments[indexPath.row]
cell.textLabel?.text = comment["text"] as? String
}
return cell
}
func keyBoardWillShow(notification: NSNotification) {
var info:NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
var keyboardHeight:CGFloat = keyboardSize.height - 40
var animationDuration:CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as! CGFloat
var contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
}
func keyBoardWillHide(notification: NSNotification) {
self.tableView.contentInset = UIEdgeInsetsZero
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if self.footerView != nil {
return self.footerView!.bounds.height
}
return 50
}
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 100))
footerView?.backgroundColor = UIColor(red: 243.0/255, green: 243.0/255, blue: 243.0/255, alpha: 1)
commentView = UITextView(frame: CGRect(x: 10, y: 5, width: tableView.bounds.width - 80 , height: 30))
commentView?.backgroundColor = UIColor.whiteColor()
commentView?.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
commentView?.layer.cornerRadius = 2
commentView?.scrollsToTop = true
footerView?.addSubview(commentView!)
let button = UIButton(frame: CGRect(x: tableView.bounds.width - 65, y: 10, width: 60 , height: 30))
button.setTitle("Reply", forState: UIControlState.Normal)
button.backgroundColor = UIColor(red: 155.0/255, green: 189.0/255, blue: 113.0/255, alpha: 1)
button.layer.cornerRadius = 5
button.addTarget(self, action: "reply", forControlEvents: UIControlEvents.TouchUpInside)
footerView?.addSubview(button)
commentView?.delegate = self
return footerView
}
func textViewDidChange(textView: UITextView) {
if (contentHeight == 0) {
contentHeight = commentView!.contentSize.height
}
if(commentView!.contentSize.height != contentHeight && commentView!.contentSize.height > footerView!.bounds.height) {
UIView.animateWithDuration(0.2, animations: { () -> Void in
let myview = self.footerView
println(self.commentView!.contentSize.height)
println(self.commentView?.font.lineHeight)
let newHeight : CGFloat = self.commentView!.font.lineHeight
let myFrame = CGRect(x: myview!.frame.minX, y: myview!.frame.minY - newHeight , width: myview!.bounds.width, height: newHeight + myview!.bounds.height)
myview?.frame = myFrame
let mycommview = self.commentView
let newCommHeight : CGFloat = self.commentView!.contentSize.height
let myCommFrame = CGRect(x: mycommview!.frame.minX, y: mycommview!.frame.minY, width: mycommview!.bounds.width, height: newCommHeight)
mycommview?.frame = myCommFrame
self.commentView = mycommview
self.footerView = myview
for item in self.footerView!.subviews {
if(item.isKindOfClass(UIButton.self)){
let button = item as! UIButton
let newY = self.footerView!.bounds.height / 2 - button.bounds.height / 2
let buttonFrame = CGRect(x: button.frame.minX, y: newY , width: button.bounds.width, height : button.bounds.height)
button.frame = buttonFrame
}
}
})
println(self.footerView?.frame)
println(self.commentView?.frame)
contentHeight = commentView!.contentSize.height
}
}
func reply() {
println(commentView?.text)
Downloader.sharedDownloader.postingAComment(commentView!.text, post: postObject)
commentView!.text = ""
}
First create footer view.
func createFooterView() -> UIView {
self.footerView = UIView(frame: CGRect(x: 0, y: 0, width: self.tblView.bounds.width, height: 100))
self.footerView?.backgroundColor = UIColor(red: 243.0/255, green: 243.0/255, blue: 243.0/255, alpha: 1)
self.commentView = UITextView(frame: CGRect(x: 10, y: 5, width: self.tblView.bounds.width - 80 , height: 30))
self.commentView?.delegate = self
self.commentView?.backgroundColor = UIColor.whiteColor()
self.commentView?.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
self.commentView?.layer.cornerRadius = 2
self.commentView?.scrollsToTop = true
self.footerView?.addSubview(self.commentView!)
let button = UIButton(frame: CGRect(x: self.tblView.bounds.width - 65, y: 10, width: 60 , height: 30))
button.setTitle("Reply", forState: UIControlState.Normal)
button.backgroundColor = UIColor(red: 155.0/255, green: 189.0/255, blue: 113.0/255, alpha: 1)
button.layer.cornerRadius = 5
button.addTarget(self, action: "reply", forControlEvents: UIControlEvents.TouchUpInside)
self.footerView?.addSubview(button)
return self.footerView
}
And in viewDidLoad()
self.tblView.tableFooterView = self.createFooterView();

Dynamically Setting Row height in Tableview works on some cells only

I have a table view where rows are populated with data from an array.
Row height is set dynamically in viewDidLoad() by calling this function:
func configureTableView() {
/* When you set the rowHeight as UITableViewAutomaticDimension, the table view knows to use the auto layout constraints to determine each cell’s height. This also reuqires a estimetedRowHeoght, an arbitary number */
println("Configure Table View called")
tableView.estimatedRowHeight = 74.0;
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
}
The data to populate each row is loading into arrays aysnrounscly from Parse.
Once data is loaded into arrays I then call:
self.tableView.reloadData();
self.configureTableView();
... in order to reload table row data and then re-conguire the row height dynamically, according to size of comments populating label within a row.
Problem is two fold:
Only some rows have the height set dynamically, other rows the row height appears to be fixed you can't view the comments if more than one line
When user scrolls the tableview, the refreshed view all rows are static, none appear to have height set dynamically, only one line of comment can be seen.
Any input appreciated
I am also using a footer view which is created programmictally with code to allow fro showing and hiding the keyboard, i think this may of something to do with it ....
// viewDidlOad
/* Setup the keyboard notifications so does not block textview for adding comments */
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyBoardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
/* Setup the contentInsets fo keyboard */
self.tableView.contentInset = UIEdgeInsetsZero
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
self.edgesForExtendedLayout = UIRectEdge.None
/* Make sure the content doesn't go below tabbar/navbar */
self.extendedLayoutIncludesOpaqueBars = true
self.automaticallyAdjustsScrollViewInsets = false
Apologies in advance but Allot of code here for setting up footer view and handling user input....
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: FOOTERHEIGHT))
footerView?.backgroundColor = UIColor(red: 243.0/255, green: 243.0/255, blue: 243.0/255, alpha: 1)
commentView = UITextView(frame: CGRect(x: 10, y: 5, width: tableView.bounds.width - 80 , height: 40))
commentView?.backgroundColor = UIColor.whiteColor()
commentView?.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
commentView?.layer.cornerRadius = 2
commentView?.scrollsToTop = true
footerView?.addSubview(commentView!)
let button = UIButton(frame: CGRect(x: tableView.bounds.width - 65, y: 10, width: 60 , height: 30))
button.setTitle("Reply", forState: UIControlState.Normal)
button.backgroundColor = UIColor(red: 155.0/255, green: 189.0/255, blue: 113.0/255, alpha: 1)
button.layer.cornerRadius = 5
button.addTarget(self, action: "reply", forControlEvents: UIControlEvents.TouchUpInside)
footerView?.addSubview(button)
commentView?.delegate = self
return footerView
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if self.footerView != nil {
return self.footerView!.bounds.height
}
return FOOTERHEIGHT
func keyBoardWillShow(notification: NSNotification) {
// Called in viewDidlOad, make sure keyoard doe snot cover add comments textview in table voew footer
var info:NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
var keyboardHeight:CGFloat = keyboardSize.height - 40
var animationDuration:CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as CGFloat
var contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
}
func keyBoardWillHide(notification: NSNotification) {
//As above
self.tableView.contentInset = UIEdgeInsetsZero
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
}
func textViewDidChange(textView: UITextView) {
// Allow for dynamic changing if TableView Footer textview size when commenst added
if (contentHeight == 0) {
contentHeight = commentView!.contentSize.height
}
if(commentView!.contentSize.height != contentHeight && commentView!.contentSize.height > footerView!.bounds.height) {
UIView.animateWithDuration(0.2, animations: { () -> Void in
let myview = self.footerView
println(self.commentView!.contentSize.height)
println(self.commentView?.font.lineHeight)
let newHeight : CGFloat = self.commentView!.font.lineHeight
let myFrame = CGRect(x: myview!.frame.minX, y: myview!.frame.minY - newHeight , width: myview!.bounds.width, height: newHeight + myview!.bounds.height)
myview?.frame = myFrame
let mycommview = self.commentView
let newCommHeight : CGFloat = self.commentView!.contentSize.height
let myCommFrame = CGRect(x: mycommview!.frame.minX, y: mycommview!.frame.minY, width: mycommview!.bounds.width, height: newCommHeight)
mycommview?.frame = myCommFrame
self.commentView = mycommview
self.footerView = myview
for item in self.footerView!.subviews {
if(item.isKindOfClass(UIButton.self)){
let button = item as UIButton
let newY = self.footerView!.bounds.height / 2 - button.bounds.height / 2
let buttonFrame = CGRect(x: button.frame.minX, y: newY , width: button.bounds.width, height : button.bounds.height)
button.frame = buttonFrame
}
}
})
println(self.footerView?.frame)
println(self.commentView?.frame)
contentHeight = commentView!.contentSize.height
}
}
func reply() {
// When Add button clicked in custom TabkeView Footer
println("User added comment: \(commentView?.text)");
self.commentView?.resignFirstResponder()
//userComments = commentView!.text;
//addComment();
self.tableView.reloadData()
//self.configureTableView();
}

Resources