UITableView with Footerview ( emdedded text view) issues - ios

I am building this simple example where there is a UITableView and a footerview associated with the uitableview. To avoid overlapping the keyboard I added the keyboard show an hide notifications and it works fine... Initially when the app load the uitextview in the footerview is placed correctly at the bottom of the UITableView.. But once type in some text and dismiss the keyboard the footerview vanishes and goes far below the viewable region. Any idea why this would happen?
On application load
On editing
After the keyboard is dismissed
At this point the uitextfield vanishes and is hidden below the tab bar. Here is the code for keyboard show and dismiss events.
func keyBoardWillShow(notification: NSNotification) {
println("Keyboard will show notification")
var info:NSDictionary = notification.userInfo!
var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
var keyboardHeight:CGFloat = keyboardSize.height
var animationDuration:CGFloat = info[UIKeyboardAnimationDurationUserInfoKey] as CGFloat
var contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
func keyBoardWillHide(notification: NSNotification) {
self.tableView.contentInset = UIEdgeInsetsZero
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero
}

Related

UITextView offset adjustment with Keyboard

I am using the following code to adjust UITextView when the keyboard is shown or hidden.
var backupTextRange:NSRange?
#objc func keyboardWillShow(notification: NSNotification) {
if let rectValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardSize = rectValue.cgRectValue.size
let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
textView.contentInset = contentInsets
textView.scrollIndicatorInsets = contentInsets
if let backupTextRange = backupTextRange {
textView.scrollRangeToVisible(backupTextRange)
NSLog("Scrolling to range \(backupTextRange)")
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
textView.contentInset = contentInsets
textView.scrollIndicatorInsets = contentInsets
backupTextRange = self.textView.selectedRange
}
So basically when I hide the keyboard to edit the font or color of selected text, I save the text range so as to scroll back when user is done choosing a font or color in another viewController (UIFontPickerController for instance). But this results in a sloppy behavior as:
Setting the contentInset of textView automatically starts a scrolling animation to the bottom of textView (not sure if this is the expected behavior),
Calling textView.scrollRangeToVisible causes the text in backupTextRange to move to top of the screen (as opposed to where it was before when it was selected). Moreover, setting this while animation is already in progress makes animation look weird.

Scroll view content inset issue on keyboardWillShow

I've following code to adjust scroll view inset. The content inside scroll view goes below the keyboard limit as shown in screen recording - https://imgur.com/a/XWfiVYX
How do I fix this so that bottom of bottomView stick to the top of keyboard and doesn't scroll up or down?
#objc func keyboardWillShow(notification:NSNotification) {
let userInfo = notification.userInfo!
let keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let kbSize = keyboardFrame.size
let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: kbSize.height, right: 0.0)
scrollView.contentInset = contentInset
scrollView.scrollIndicatorInsets = contentInset
}
Using scrollView.contentInset will not fix you view above kb, it will scroll up and down as you are seeing it in your case. This solution is from Apple's code which is good to show the textView up above kb only and doesn't stick the bottom of text view above kb.
You need to move up the entire self.view by kb height.

Want ability to manually scroll to pull textfield above keyboard

The problem is apparently when a user sees that the keyboard is blocking textfields that they want to type in, instead of hitting return, or closing the keyboard and tapping on the next field, they try to pan to the next field. Since my content matches the size of the iPad, the scrollview doesn't automatically scroll when the user tries to pan. Honestly, I don't want it to scroll unless the keyboard is on-screen anyway.
However, enabling scrolling on the scrollview doesn't solve the problem; it still won't respond to panning even in that case. Neither does making the viewcontroller the delegate of the scrollview and overriding the function scrollViewDidScroll. How do I get the scrollview to enable panning, particularly only when the keyboard is enabled?
Since a solution has been posted that doesn't quite work, I think I will post my keyboardWillBeShown and keyboardWillBeHidden code:
func keyboardWillBeShown(_ sender: Notification)
{
self.myScrollView.isScrollEnabled = true
let info: NSDictionary = (sender as NSNotification).userInfo! as NSDictionary
let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.cgRectValue.size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
self.myScrollView.contentInset = contentInsets
self.myScrollView.scrollIndicatorInsets = contentInsets
self.myScrollView.scrollRectToVisible(self.myScrollView.frame, animated: true)
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextFieldRect: CGRect? = activeField?.frame
let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
if activeTextFieldOrigin != nil
{
if (!aRect.contains(activeTextFieldOrigin!))
{
let scrollpoint : CGPoint = CGPoint(x: 0.0, y: activeField!.frame.origin.y - keyboardSize.height)
self.myScrollView.setContentOffset(scrollpoint, animated: true)//.scrollRectToVisible((activeField?.frame)!, animated: true)
}
}
}
func keyboardWillBeHidden(_ sender: Notification)
{
myScrollView.isScrollEnabled = false
let contentInsets: UIEdgeInsets = UIEdgeInsets.zero
myScrollView.contentInset = contentInsets
myScrollView.scrollIndicatorInsets = contentInsets
}
Try this,
Declare variables to be used
var originalViewCGRect: CGRect?
var originalOffset: CGPoint!
in viewDidLoad add keyboard observers
NotificationCenter.default.addObserver(self
, selector: #selector(keyboardWillAppear(_:))
, name: NSNotification.Name.UIKeyboardWillShow
, object: nil)
NotificationCenter.default.addObserver(self
, selector: #selector(keyboardWillDisappear(_:))
, name: NSNotification.Name.UIKeyboardWillHide
, object: nil)
And finally, add these functions
func keyboardWillAppear(_ notification: Foundation.Notification){
self.scrollView.scrollRectToVisible(self.scrollView.frame, animated: true)
let keyboardSize:CGSize = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue.size
let insets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
self.scrollView.contentInset = insets
}
func keyboardWillDisappear(_ notification: Foundation.Notification){
let beginFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let endFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let delta = (endFrame.origin.y - beginFrame.origin.y)
self.view.frame = self.originalViewCGRect!
self.scrollView.setContentOffset(CGPoint(x: 0, y: max(self.scrollView.contentOffset.y - delta, 0)), animated: true)
}
In summary, this will adjust the content inset of the scrollview when the keyboard is shown and/or hidden.
Hope this helps.
EDIT
Fixed adjustments
I figured out how to get what I want. Set myScrollView.contentSize to be as big as the screen plus the keyboard when the keyboard is shown, and reduce the size back to what it was when keyboard is hidden. Then make the view controller a UIScrollViewDelegate, set myScrollView.delegate = self, and implement scrollViewDidScroll so that if a textfield is editing, and that textfield isn't blank, then change which text field is the first responder. Piece of cake once you realize the trick of setting .contentSize!

Keyboard management blocking UITextView

So I followed apple guidelines on moving text above the keyboard, this works fine when the textfields are on scrollview, however the scrollview contains a collection view and that collection view loads a nib with textfields populated within it, they are all assigned as the delegate and when they are pressed the didEdit/endEdit functions of the delegate do fire however the keyboard management code doesn't work as expected... here is the keyboard management code
http://creativecoefficient.net/swift/keyboard-management/
heres a link to the code am using..
func keyboardWillBeShown(sender: NSNotification) {
print("KEYBOARD SHOWN")
let info: NSDictionary = sender.userInfo!
let value: NSValue = info.valueForKey(UIKeyboardFrameBeginUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.CGRectValue().size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0,keyboardSize.height, 0.0)
print(keyboardSize.height)
ScrollView.contentInset = contentInsets
ScrollView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect: CGRect = self.view.frame
aRect.size.height -= keyboardSize.height
let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
let dHeight = displayView.frame.height
ScrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
}
The problem with this code is that the activeTextfield works well with the textfields of the view, i get these points printed when i click on the textfield
activetextfield Frame
(0.0, 20.5, 150.0, 20.5)
but when i click on the collection view nib textfields i get these points
0.0, 0.0, 259.5, 30.0
I believe this is the reason the keyboard is blocking the textfields, the activetextfieldRect is giving the wrong coordinates to
ScrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
can someone give me some direction on how to go about fixing this?
Yes, you're right. scrollRectToVisible receive wrong coordinates, and this is why it is not work.
To achieve your goal consider using scrollToItemAtIndexPath(_:atScrollPosition:animated:). All what you need is IndexPath of cell to move. And I guess you can put that info in tag property of your textField (for instance).
Something like this:
// inside cellForItem..
cell.textField.tag = indexPath.item
// inside keyboardWillShown
let indexPath = NSIndexPath(forItem: activeTextField.tag inSection: 0) // assume that you have one section
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Top, animated: true) // or try .Center position
func keyboardWillBeShown(sender: NSNotification) {
print("KEYBOARD SHOWN")
let info: NSDictionary = sender.userInfo!
let value: NSValue = info.valueForKey(UIKeyboardFrameBeginUserInfoKey) as! NSValue
let keyboardSize: CGSize = value.CGRectValue().size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
ScrollView.contentInset = contentInsets
ScrollView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect: CGRect = self.ScrollView.frame
aRect.size.height -= keyboardSize.height
let activeTextFieldRect: CGRect? = activeTextField?.frame
let activeTextFieldOrigin: CGPoint? = TextfieldPoint
if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
ScrollView.scrollRectToVisible(testBox, animated:true)
}
}
// Called when the UIKeyboardWillHideNotification is sent
func keyboardWillBeHidden(sender: NSNotification) {
print("KEYBOARD HIDDEN")
let contentInsets: UIEdgeInsets = UIEdgeInsetsZero
ScrollView.contentInset = contentInsets
ScrollView.scrollIndicatorInsets = contentInsets
}
func textFieldDidBeginEditing(textField: UITextField) {
let point: CGPoint = textField.convertPoint(CGPointZero, toView: self.ScrollView);
TextfieldPoint = point
testBox = CGRectMake(point.x, point.y, textField.frame.width, 100 );
//let indexPath:NSIndexPath? = collview1.indexPathForItemAtPoint(point)
print("TEXTFIELD EDIT")
activeTextField = textField
print(activeTextField)
ScrollView.scrollEnabled = true
}
func textFieldDidEndEditing(textField: UITextField) {
print("TEXTFIELD STOP EDIT")
activeTextField = nil
ScrollView.scrollEnabled = false
}
it works just really messy i guess, i got the point where textfield was, made CGRect out of it, if the keyboard overlaps the text, the view adjusts, tested on iPhone 4s to 6s plus, works fine

Scroll UIScrollView on selection UITextField, can't get the right sizes

What I've got is a UIScrollView with a containerview inside it. This has a UITableViewcontroller embedded that contains static cells. I'd like to scroll the UIScrollView when I'm selecting a UITextField inside the static cells. I tried it two ways, 1. calculating the position, 2. calculating the cell index. Both ways I keep getting the same values when I'm selection an any UIField. Can someone help me to get this fixed?
I used this question:
How do I scroll the UIScrollView when the keyboard appears?
func keyboardWasShown(notification : NSNotification){
var info = notification.userInfo
// var kbSize = info(UIKeyboa
if let userInfo = notification.userInfo {
if let kbSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
//first approach
println("---- approach 1 ------")
var activeField = self.container?.groupField.superview?.superview
println(activeField!.frame.origin)
//prints (110.0, 5.0)
//second approach
println("---- approach 2 ------")
var cell = self.container?.groupField.superview?.superview as! UITableViewCell
var table = self.container?.view as! UITableView
var index = table.indexPathForCell(cell)
println("index: \(index?.row)")
//prints always 4
var aRect = self.view.frame
aRect.size.height -= kbSize.height
// println("aRect: \(aRect)")
if (!CGRectContainsPoint(aRect, activeField!.frame.origin) ) {
println("ActiveField: \(activeField!.frame.origin.y)")
var scrollPoint = CGPointMake(0.0, activeField!.frame.origin.y-kbSize.height)
scrollView.setContentOffset(scrollPoint, animated:true)
}
}
}
}
It was a stupid mistake, I selected a default field as activefield
I replaced:
var activeField = self.container?.groupField.superview?.superview
to:
var activeField = self.container?.activeField.superview?.superview

Resources