how to manage scrolling of table view containing text fields - objective-c

When I try to scroll and edit the cells at the bottom of the UITableView, I can't manage to get my cells properly positioned above the keyboard. Actually keyboard hides half of the table view.
Also i created a custom cell class separately for my cells. So text fields delegates are available on that class only. i can't use them in my table biew's view controller
I have seen many answers talking about changing view sizes,etc... but none of them has worked nicely so far.
could anybody help me with this with a piece of code

An easier way to do this now (don't know how long this has been available): if you're overriding viewWillAppear, make sure to include at the top
[super viewWillAppear:animated];
I was all set to start listening to keyboard events and setting and removing constraints and just this one line eliminated all that other code.

You want to adjust the scrollView component of the UITableView. Set your view controller to respond to Keyboard notifications. Like this :
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Then create a keyboardWillShow: function and adjust the tableview by manipulating the tableView.scrollview.contentOffset (it might be tableView.contentOffset im not near xcode). Make sure you make a keyboardWillHide function to adjust it back to 0,0.

Related

Handle device rotation for "More" UINavigationController in UITabBarController.moreNavigationController

I have an app which has to work in both portrait and landscape more and the UITabBar should adjust to current orientation (it has custom background and selected items). So, for the rest of views I just override the - (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation method and it works perfectly.
How would I do that for the .moreNavigationController of UITabBarController ? I've tried adding an observer (the selector is in extension of UITabBarController):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:self.moreNavigationController];
but it never get called.
Am I missing something or what would be the best way to handle this situation ?
Solution: somewhy UIDeviceOrientation is not firing correctly, so better to use statusBarOrientation, works as a charm.
the final code which work is this:
in main UITabBarController, viewDidLoad:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
the didRotate selector method:
- (void) didRotate:(NSNotification *)notification{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsPortrait(orientation)) {
// Portrait
} else {
// Landscape
}
}
Thanks for help.
You are registering your UITabBarController for a notification which never gets posted. Take a look at the documentation NSNotificationCenter Reference for the addObserver:selector:name:object method
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender
notificationSender:
The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.
If you pass nil, the notification center doesn’t use a notification’s sender to decide whether to deliver it to the observer.
so, if you specify the . moreNavigationController as the sender, you wont get those notifications, because it never posts such ones. Instead pass nil to ignore the sender and listen to the status bar change regardless of who sent it.
By the way, in this SO Answer is a summary of how you can react to orientation change.
And at last. If it still doesn't work, you can try this:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Yes, you forgot to post notification, which will call you own notification:
[[NSNotificationCenter defaultCenter] postNotificationName: UIApplicationDidChangeStatusBarOrientationNotification object:self];
or if you dont wont to send anything just set object as nil:
[[NSNotificationCenter defaultCenter] postNotificationName: UIApplicationDidChangeStatusBarOrientationNotification object:nil];
The best way to implement the same is first addObserver and then remove observer to avoid the crash:-
-(void)viewDidLoad{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
//Now Remove Observer
-(void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self #"UIDeviceOrientationDidChangeNotification" object:nil];
}

Calling UIKeyboard method on UITextView and not UITextFields

I have view with a UITextView for comments on the bottom. Since its on the bottom of the page, whenever someone edits it, a method is called to shift the view of the page, so that you can still see the comment box. My problem is that the same method also gets called when user are editing UITextFields.
Here's what I have. First I declare a notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
Then the method itself
- (void)keyboardWillShow:(NSNotification *)notif{
...
}
My first thought was to add a condition, to check and see if the object was a TextView, and only then execute the code. But since I am not passing the object to the method, is there anyway to tell the method what type of object I am dealing with
Text fields and text views also send notifications. In the textFieldShouldBeginEditing and the textViewShouldBeginEditing implementations you could set a flag that you can read in your implementation of the keyboardWillShow method -- the keyboard notification is sent after the text field or text view notifications.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
self.sender = #"text field";
return YES;
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
self.sender = #"text view";
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
}
- (void)keyboardWillShow:(NSNotification *)notif{
NSLog(#"%#",self.sender);
}

iPad : How to know Return key of iPad keyboard is pressed ? Please check image

I want to know that which method will be called when the following key is pressed.
I want to start action on above key press.
How do I know this is pressed ?
Observe the UIKeyboardDidHideNotification notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
And...
- (void)keyboardDidHide:(NSNotification *)aNotification {
}
You can also change it to UIKeyboardWillHideNotification if you need to be notified BEFORE the keyboard starts to disappear.
That's not a return key. Return key is the one above it. That's simply a button that dismisses the keyboard and you can't recognize it via standard text input methods. You need to register for UIKeyboardWillHideNotification notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
and implement that method:
- (void)keyboardWillHide:(NSNotification *)notification
{
// do whatever you want to do when keyboard dismiss button is tapped
}
Not sure if it's exactly what you are looking for, but you can try using notifications. Don't have Mac nearby atm, so just copy-pasting the code from github. I have that code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
and then 2 methods:
- (void)keyboardWillShow:(NSNotification *)notification {
}
- (void)keyboardWillHide:(NSNotification *)notification {
}
Hope it helps
Use keyboard hide UIKeyboardWillHideNotification notification.
Example.

Removing a NSNotificationCenter observer in iOS 5 ARC

I have an iOS 5 ARC-based project, and am having difficulty about where I should be removing the observer for the NSNotificationCenter observations which I have registered within a UIViewController. Similar posts on SO have said this should be done in the -dealloc method. Even though this method is not required in ARC projects I have added it with the following code:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
As a test, I open the UIViewController (within a UINavigationController), do some things which trigger the notifications, and then pop it off the stack by tapping the Back button. I then reopen the UIViewController, and do some more things to trigger the notifications, but notice that each callback is being called twice - an indication that the previous notifications have not been deregistered. Repeating this procedure just causes each callback to be called more than more times, so they appear to never be deregistering.
Any help would be appreciated!
It's pretty clear your dealloc method isn't being called (nor is the removeObserver call).
Why not remove your UIViewController's observer in the viewDidUnload: or viewWillDisappear: methods?
If your dealloc isn't being called, it's likely because someone is still holding a reference to the view controller. Perhaps you need to mark something as __weak? You can use the allocations instrument to help track down what's holding on to your view controller.
"I also need the notification callbacks to still be fired if the view is off-screen" -> you may need to register UIApplicationWillEnterForegroundNotification. If so, let try this:
- (void)viewWillAppear:(BOOL)animated {
NSLog(#"viewWillAppear");
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
NSLog(#"viewWillDisappear");
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(#"applicationWillEnterForeground");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
// do your stuff here
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"applicationDidEnterBackground");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
The idea is adding or removing UIApplicationDidEnterBackgroundNotification whenever coming in and out of your screen. We just register UIApplicationWillEnterForegroundNotification when the app enter background and remove once it's back. Be noticed that we just remove UIApplicationDidEnterBackgroundNotification when viewWillDisappear.
My dealloc() is not called by somehow, so I found this way, hope it useful for you too.
Enjoy :)

How to reloadData?

I am not dumb and I know how to reload data. I am in a tricky situation where I have a UIView inside another UIView both named OHGridView. I have to keep them named the same way.
With the OHGridView example code, the refresh looked a little like this:
[(OHGridView *)self.view reloadData];
But now that I added a UIView, it no longer works.
Any help is appreciated!
Edit:
Code removed
The NSNotificationCenter may be what you need. You can register for events (eg a perform update event) and then post these events from anywhere. These go to the notification center and then to your class/view. When the event is received, you just do what is needed.
The docs are here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
Inside the OHGridView you would call during initialization:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(ReloadNotification:) name:#"ReloadOHGridView" object:nil];
Then, just define the method:
- (void)ReloadNotification:(NSNotification *)notification
{
[self reloadData];
}
So, when you want an update to occur, you then just call:
[[NSNotificationCenter defaultCenter] postNotificationName:#"ReloadOHGridView" object:self];
When you deallocate the OHGridView you should remove the observer:
[[NSNotificationCenter defaultCenter] removeObserver:self];