I'm trying to implement the comment view controller.
I want using the auto layout via the storyboard.
My question is...
When I tap the input text..then keyboard will move up...but input text is not move up..
Keyboard is overlapping the text input..
Here is TableViewController.swift
import UIKit
import Parse
var commentUUID = [String]()
var commentOwner = [String]()
class CommentViewController: UIViewController, UITextViewDelegate, UITableViewDelegate, UITableViewDataSource{
//UI Objects
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var commentTextView: UITextView!
@IBOutlet weak var sendButton: UIButton!
var refresher = UIRefreshControl()
//values for reseting UI to default
var tableViewHeight : CGFloat = 0
var commentY : CGFloat = 0
var commentHeight : CGFloat = 0
//arryas to hold server data
var usernameArray = [String]()
var profileArray = [PFFile]()
var commentArray = [String]()
var dateArray = [NSDate?]()
//variable to hold keyboard frame
var keyboard = CGRect()
//page size
var page : Int32 = 15
override func viewDidLoad() {
super.viewDidLoad()
tableView.backgroundColor = .redColor()
//title at the top
self.navigationItem.title = "COMMENTS"
self.navigationItem.hidesBackButton = true
let backButton = UIBarButtonItem(title: "back", style: .Plain, target: self, action: #selector(CommentViewController.back(_:)))
self.navigationItem.leftBarButtonItem=backButton
//swipe to go back
let backSwipe = UISwipeGestureRecognizer(target: self, action: #selector(CommentViewController.back(_:)))
backSwipe.direction=UISwipeGestureRecognizerDirection.Right
self.view.addGestureRecognizer(backSwipe)
// catch notification if the keyboard is shown or hidden
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(CommentViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(CommentViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
//disable button from the beginning
sendButton.enabled = false
//call function
alignment()
loadComments()
}
//I think it is not affect on the layout...
func configureTableView() {
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160.0
}
// preload func
override func viewWillAppear(animated: Bool) {
//hide bottom bar
self.tabBarController?.tabBar.hidden = true
}
// postload func
override func viewWillDisappear(animated: Bool) {
self.tabBarController?.tabBar.hidden = false
}
//func loading when keyboard is shown
func keyboardWillShow(notification : NSNotification){
//define keyboard frame size
keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRectValue)!
//move UI up
UIView.animateWithDuration(0.4){ () -> Void in
self.tableView.frame.size.height = self.tableViewHeight - self.keyboard.height - self.commentTextView.frame.size.height + self.commentHeight
print("keyboard show")
self.commentTextView.frame.origin.y = self.commentY - self.keyboard.height - self.commentTextView.frame.size.height + self.commentHeight
self.sendButton.frame.origin.y = self.commentTextView.frame.origin.y
self.commentTextView.frame.origin.y = 250
}
}
//func loading when keyboard is hidden
func keyboardWillHide(notification : NSNotification){
//move UI down
UIView.animateWithDuration(0.4){() -> Void in
self.tableView.frame.size.height = self.tableViewHeight
self.commentTextView.frame.origin.y = self.commentY
self.sendButton.frame.origin.y = self.commentY
}
}
//alignment function
func alignment(){
let width = self.view.frame.size.width
let height = self.view.frame.size.height
tableView.frame = CGRectMake(0, 0, width, height - self.navigationController!.navigationBar.frame.size.height)
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160.0
commentTextView.layer.cornerRadius = commentTextView.frame.size.width / 50
//delegates
commentTextView.delegate = self
tableView.delegate = self
tableView.dataSource = self
//assign reseting values
tableViewHeight = tableView.frame.size.height
commentHeight = commentTextView.frame.size.height
commentY = commentTextView.frame.origin.y
}
//while writing something
func textViewDidChange(textView: UITextView) {
//disable button if entered no text
let spacing = NSCharacterSet.whitespaceAndNewlineCharacterSet()
//It shown when user entered type
if !commentTextView.text.stringByTrimmingCharactersInSet(spacing).isEmpty{
sendButton.enabled = true
}else {
sendButton.enabled = false
}
// + paragraph
if textView.contentSize.height > textView.frame.size.height && textView.frame.height < 130{
//find difference to add
let difference = textView.contentSize.height - textView.frame.size.height
//redefine frame of commentText
textView.frame.origin.y = textView.frame.origin.y - difference
textView.frame.size.height = textView.contentSize.height
//move up tableView
if textView.contentSize.height + keyboard.height + commentY >= tableView.frame.size.height {
tableView.frame.size.height = tableView.frame.size.height - difference
}
}
// - parapraph
else if textView.contentSize.height < textView.frame.size.height {
//find difference to deduct
let difference = textView.frame.size.height - textView.contentSize.height
//redefine frame of commentText
textView.frame.origin.y = textView.frame.origin.y + difference
textView.frame.size.height = textView.contentSize.height
//move down tableview
if textView.contentSize.height + keyboard.height + commentY > tableView.frame.size.height {
tableView.frame.size.height = tableView.frame.size.height + difference
}
}
}
//load comments function
func loadComments(){
//STEP 1. Count total comments in order to skip all except page size
let countQuery = PFQuery(className: "comments")
countQuery.whereKey("to", equalTo: commentUUID.last!)
countQuery.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//if comments on the server for current post are more than (page size 15) implement pull to refresh func
if self.page < count {
self.refresher.addTarget(self, action: #selector(CommentViewController.loadMore), forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(self.refresher)
}
//STEP 2. Request last (page size 15) comments
let query = PFQuery(className: "comments")
query.whereKey("to", equalTo: commentUUID.last!)
query.skip = count - self.page
query.addAscendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.commentArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
//find related object
for object in objects!{
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.commentArray.append(object.objectForKey("comment") as! String)
self.dateArray.append(object.createdAt)
self.tableView.reloadData()
//scroll to bottom
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: self.commentArray.count - 1, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
}
}else {
print(error?.localizedDescription)
}
})
})
}
//Pagenation
func loadMore(){
//STEP 1. Count total comments in order to skip all except page size
let countQuery = PFQuery(className: "comments")
countQuery.whereKey("to", equalTo: commentUUID.last!)
countQuery.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//self refresher
self.refresher.endRefreshing()
//remove refresher if loaded all comments
if self.page >= count {
self.refresher.removeFromSuperview()
}
//STEP2. Load more comments
if self.page < count {
//increase page to laod 30 as first paging
self.page = self.page + 15
//request existing comments from the server
let query = PFQuery(className: "comments")
query.whereKey("to", equalTo: commentUUID.last!)
query.skip = count - self.page
query.addAscendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error==nil{
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.commentArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.commentArray.append(object.objectForKey("comments") as! String)
self.dateArray.append(object.createdAt)
self.tableView.reloadData()
}
}else {
print(error?.localizedDescription)
}
})
}
})
}
//Send Button Tapped
@IBAction func sendButtonTapped(sender: AnyObject) {
print("send tapped")
//STEP1. Add row in tableView
usernameArray.append(PFUser.currentUser()!.username!)
profileArray.append(PFUser.currentUser()?.objectForKey("profileImg") as! PFFile)
dateArray.append(NSDate())
commentArray.append(commentTextView.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()))
tableView.reloadData()
//STEP2. Send comment to server
let commentObj = PFObject(className: "comments")
commentObj["to"] = commentUUID.last
commentObj["username"] = PFUser.currentUser()?.username
commentObj["profileImg"] = PFUser.currentUser()?.valueForKey("profileImg")
commentObj["comment"] = commentTextView.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
commentObj.saveEventually()
//Scroll to bottom
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forItem: commentArray.count - 1, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
//STEP 3. Reset UI
sendButton.enabled = false
commentTextView.text = ""
commentTextView.frame.size.height = commentHeight
commentTextView.frame.origin.y = sendButton.frame.origin.y
tableView.frame.size.height = self.tableViewHeight - self.keyboard.height - self.commentTextView.frame.size.height + self.commentHeight
}
//tableview
//cell numb
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return commentArray.count
}
//cell height
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
//Cell config
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//declaire cell
let cell = tableView.dequeueReusableCellWithIdentifier("commentCell") as! CommentTableViewCell
cell.usernameButton.setTitle(usernameArray[indexPath.row], forState: .Normal)
cell.usernameButton.sizeToFit()
cell.commentLabel.text = commentArray[indexPath.row]
profileArray[indexPath.row].getDataInBackgroundWithBlock({(data:NSData?, error:NSError?) -> Void in
cell.profileImagevView.image = UIImage(data: data!)
})
//calculate date
let from = dateArray[indexPath.row]
let now = NSDate()
let components : NSCalendarUnit = [.Second, .Minute, .Hour, .Day, .WeekOfMonth]
let difference = NSCalendar.currentCalendar().components(components, fromDate: from!, toDate: now, options: [])
if difference.second <= 0 {
cell.dateLabel.text = "now"
}
if difference.second > 0 && difference.minute == 0 {
cell.dateLabel.text = "\(difference.second)s"
}
if difference.minute > 0 && difference.hour == 0 {
cell.dateLabel.text = "\(difference.minute)m"
}
if difference.hour > 0 && difference.day == 0 {
cell.dateLabel.text = "\(difference.hour)h"
}
if difference.day > 0 && difference.weekOfMonth == 0 {
cell.dateLabel.text = "\(difference.day)d."
}
if difference.weekOfMonth > 0 {
cell.dateLabel.text = "\(difference.weekOfMonth)w."
}
cell.usernameButton.layer.setValue(indexPath, forKey: "index")
return cell
}
//clicked username button
@IBAction func usernameButtonTapped(sender: AnyObject) {
//call index of current button
let i = sender.layer.valueForKey("index") as! NSIndexPath
//Call cell to call further cell data
let cell = tableView.cellForRowAtIndexPath(i) as! CommentTableViewCell
//if user tapped on his username go home, else go guest
if cell.usernameButton.titleLabel?.text == PFUser.currentUser()?.username {
let home = self.storyboard?.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
self.navigationController?.pushViewController(home, animated: true)
}else {
guestname.append(cell.usernameButton.titleLabel!.text!)
let guest = self.storyboard?.instantiateViewControllerWithIdentifier("GuestHomeViewController") as! GuestHomeViewController
self.navigationController?.pushViewController(guest, animated: true)
}
}
//go back
func back(sender : UIBarButtonItem){
//push back
self.navigationController?.popViewControllerAnimated(true)
//clean comment uuid from holding information
if !commentUUID.isEmpty{
commentUUID.removeLast()
}
//clean comment owner from last holding information
if !commentOwner.isEmpty{
commentOwner.removeLast()
}
}
}
And It is my cell controller
import UIKit
class CommentTableViewCell: UITableViewCell {
@IBOutlet weak var profileImagevView: UIImageView!
@IBOutlet weak var usernameButton: UIButton!
@IBOutlet weak var commentLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!
//default func
override func awakeFromNib() {
super.awakeFromNib()
//round profile
profileImagevView.layer.cornerRadius = profileImagevView.frame.size.width/2
profileImagevView.clipsToBounds = true
}
}