tableView resize problem when pushing another view while keyboard is showing - iphone

I have a tableview controller under a navigation controller. Some of my table cells contain text fields, so when I tap on them, a keyboard will show up and automatically resize (shrink) the bounds of my tableview. The bounds is then restored when the keyboard is dismissed programmatically by calling resignFirstResponder on my text field.
Some of my cells would push a new view controller into the view stack when tapped on, so I first resign my current textfield before pushing the view controller:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (currentEditingTextField != nil) {
[currentEditingTextField resignFirstResponder];
currentEditingTextField = nil;
}
return indexPath;
}
The problem is when I navigate back to my table view, the bounds of the tableview is sized as if the keyboard is still there. I know this because the scroll indicator only reaches right above where the keyboard was and there is empty view space below the table view.
Anybody experienced this and know of a solution? Thanks

I had the same issue. I found that I need to prevent call [UIView viewWillDisappear:] before the keyboard hides.
My solutions for this.
// useful method, thus I don't need to remember current first responder
#interface UIView (FindAndResignFirstResponder)
- (BOOL)findAndResignFirstResonder;
#end
// ---
#implementation UIView (FindAndResignFirstResponder)
// http://stackoverflow.com/questions/1823317/how-do-i-legally-get-the-current-first-responder-on-the-screen-on-an-iphone
- (BOOL)findAndResignFirstResonder {
if (self.isFirstResponder) {
return [self resignFirstResponder];
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResonder]) {
return YES;
}
}
return NO;
}
#end
// ---
#interface MyTableViewController : UITableViewController {
// some booleans required to track state of keyboard and view
BOOL hidingKeyboard;
BOOL viewWillDisappear;
BOOL viewWillDisappearAnimated;
}
// methods for keyboard event handling
- (void)keyboardWillHide:(id)sender;
- (void)keyboardDidHide:(id)sender;
#end
// ---
#implementation MyTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// adding observer for keyboard events (notifications)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
hidingKeyboard = NO;
viewWillDisappear = NO;
}
- (void)viewDidUnload {
[super viewDidUnload];
// removing observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewWillDisappear:(BOOL)animated {
// finding and resigning first responder
[self.view findAndResignFirstResonder];
if (hidingKeyboard) {
// if keyboard hide animation in process,
// remembering to run [super viewWillDisappear:] after keyboard hides
viewWillDisappear = YES;
viewWillDisappearAnimated = animated;
} else {
// if there is no keyboard hide animation,
// calling super immediately
[super viewWillDisappear:animated];
}
}
- (void)keyboardWillHide:(id)sender {
hidingKeyboard = YES;
}
- (void)keyboardDidHide:(id)sender {
hidingKeyboard = NO;
if (viewWillDisappear) {
// calling [super viewWillAppear:] after keyboard hides, if required
viewWillDisappear = NO;
[super viewWillAppear:viewWillDisappearAnimated];
}
}
#end

Related

Call [tableView reloadData]; on a viewController from a modalViewController

I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.

Removing a second viewcontroller's view after dissmissing mail controller

A second viewcontroller has mailcontroller and after finishing mail, it post a message to the mainviewcontroller to remove the secondviewcontroller's view. but it's not happening. The mailcontroller appearing and disappearing seem to interferes with finish function of the mainviewcontroller.
secondviewcontroller:
[self dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"finish" object:nil];
mainviewcontroller:
-(void) finish:(NSNotification *)notif {
[MyviewController.view removeFromSuperview];
}
The removal of the second view controller should be delayed until your modal controller is really removed. What I have done is following:
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = YES;
And then:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ( m_shouldHide )
{
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = NO;
}
}

How to use presentModalViewController in iPhone/iPad?

Hi i am very new in iPhone/iPad developmet.
In my application on clicking of button in want to show view controller like presentModalViewController and i am able to do that which contains the UITableView with some numbers of values. on selecting particulate row i want to pass values to controller which is behind that controller.
for that i am using apple sample application PhotoPicker code. http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html
But i am not able to understand the what i did wrong in my code.
I am not able to go in the code which is in the MyViewController.m
- (void)didFinishWithCamera
{
[self dismissModalViewControllerAnimated:YES];
//Here is my some logic
}
can any one help me for this...how to call this function from OverlayViewController?
please refer above link and guide me or give me some steps or guide me for the same.
use delegation.
I use something like this in a app I'm writing at the moment:
// MySecretSelectionViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[delegate mySecretSelectionViewController:self didSelectObject:[self objectForIndexPath:indexPath] atIndexPath:indexPath];
}
// MyViewController.m
- (void)mySecretSelectionViewController:(MySecretSelectionViewController *)es didSelectObject:(MySecretObject *)object atIndexPath:(NSIndexPath *)indexPath {
// do something with the selected object
[self dismissModalViewControllerAnimated:YES];
}
- (void)showMySecretSelectionViewController:(id)sender {
MySecretSelectionViewController *vc = ...
vc.delegate = self;
// present ViewController
}
You can also do this with use of NSNotificationCenter.
Inside MyViewController.m:
- (void)viewDidLoad
{
// your code
// Add observers
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishWithCamera) name:#"YourObserverName" object:nil];
}
+ (void)callDidFinishWithCamera
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"YourObserverName" object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// your code
}
From OverlayViewController.m:
[MyViewController callDidFinishWithCamera];
Use the above class method to call didFinishWithCamera in MyViewController from OverlayViewController

how to add done button in keypad

i need to add button done on keypad.
Apple does n't provide such felicity but some of application i found that done ,next,previous buttons.
like this.
how can i add these and how can i give click event to them.
can any one please help me.
1.Define the done button (= return key):
textField.returnKeyType = UIReturnKeyDone;
2.Add the action-listener:
[textField addTarget:self action:#selector(textFieldDoneEditing:) forControlEvents:UIControlEventEditingDidEndOnExit];
3.Define the action-event:
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
Have fun!
EDIT:
Here you can find detailed instructions how to add a Toolbar with Next & Previous above UITextField Keyboard:
http://www.randomsequence.com/articles/adding-a-toolbar-with-next-previous-above-uitextfield-keyboard-iphone/
EDIT2:
Now, I have a really great example for you: "This view extends UITextView adding on top of the keyboard associated with this UITextView a toolbar with a « Done » Button"
I check the code and it is a lot of easier than the first example:
http://blog.demay-fr.net/2009/07/cocoa-how-to-add-a-toolbar-with-button-on-top-of-a-uitextview-in-order-to-add-a-dismiss-button/
EDIT3:
Hmmm, no, I doesn't test to code. But I will test it now!
1.Problem: the right initialization. If I add the UITextView in IB, initWithCoder gets called:
- (id)init {
NSLog(#"init");
if (self = [super init]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSLog(#"initWithCoder");
if (self = [super initWithCoder:decoder]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"initWithFrame");
if (self = [super initWithFrame:frame]) {
//register a specific method on keyboard appearence
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
return self;
}
2.Problem: There's no view with the the Prefix "UIKeyboard":
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
NSLog(#"keyboardWindow = %#", keyboardWindow);
for (UIView *keyboard in [keyboardWindow subviews]) {
NSLog(#"keyboard = %#", keyboard);
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES) {
// THERE'S NO VIEW 'UIKeyboard'!!!
}
}
}
The code doesn't work, I'm sorry... I don't know why there's no view "UIKeyboard"... Maybe the first example will help you at this point and you can build your own solution.

dismissing the NumberPad keyboard from a UIScrollView

I have an application with UIScrollView added as a subview of UIView. This Scroll view has a textfield with keyboard type set to numberPad.
Now the problem is , i want to dismiss the keyboard when i tap anywhere else in the scroll view. how can i do this ... ?
Just call the textField's resignFirstResponder in the touch handler.
(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[myTextField resignFirstResponder];
}
When I added the gesture to a subclass of UIScrollView, I was having problems with the various gestures in my view tree interfering with each other, such as being able to click on subviews, scroll the view, and have the keyboard dismiss in all cases. I came up with this solution, which can be setup from a superclass of UIScrollView or from a UIViewController.
The DismissKeyboardTapGesture class uses ARC, works with any text fields under the view, and doesn't take over any clicks from subviews like buttons. Also takes advantage of iOS7 scrolling effect to dismiss keyboard.
Setting up from UISScrollView superclass:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self];
or from UIViewController:
_dismissKeyboard = [[DismissKeyboardTapGesture alloc] initWithView:self.view];
Here is the class:
#interface DismissKeyboardTapGesture : NSObject <UIGestureRecognizerDelegate>
#end
#implementation DismissKeyboardTapGesture
- (id)initWithView:(UIView *)view
{
self = [super init];
if (self) {
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTap.cancelsTouchesInView = NO;
singleTap.delegate = self;
[view addGestureRecognizer:singleTap];
if ([view respondsToSelector:#selector(setKeyboardDismissMode:)]) {
// Bonus effect to dismiss keyboard by scrolling
((UIScrollView *)view).keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
}
}
return self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// Don't stop any existing gestures in our view from working
if (otherGestureRecognizer.view == gestureRecognizer.view) {
return YES;
}
return NO;
}
- (void)singleTap:(UIGestureRecognizer*)gestureRecognizer
{
// Close keyboard for any text edit views that are children of the main view
[gestureRecognizer.view endEditing:YES];
}
#end