0

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..

enter image description here

enter image description here

enter image description here

enter image description here

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

}
}
Umair Afzal
  • 4,947
  • 5
  • 25
  • 50
Shawn Baek
  • 1,928
  • 3
  • 20
  • 34

2 Answers2

1

Two comments:

  1. Use UIKeyboardDidShowNotification instead of UIKeyboardWillShowNotification
  2. Do not modify frame directly when you're using auto layout. Just link your bottom layout constraint to the controller and change a constant value when needed.
Arsen
  • 10,815
  • 2
  • 34
  • 46
1

Try this:

    self.tableView.frame.size.height = self.view.frame.height - keyboard.height - self.tableView.frame.size.height

    print("keyboard show")

    self.commentTextView.frame = CGRect(self.commentTextView.frame.minX, self.commentTextView.frame.minY - keyboard.height, self.commentTextView.frame.width, self.commentTextView.frame.height)

    self.sendButton.frame.origin.y = self.commentTextView.frame.origin.y

Edit

@Arsen's Answer makes much more sense and probably much easier, by the way :P But this should work the same.

impression7vx
  • 1,728
  • 1
  • 20
  • 50