XCODE 5+ ...当第二行添加时,如何阻止TextView中的文本跳到键盘上方?

时间:2014-10-04 23:24:44

标签: ios xcode keyboard uitextview

相对新手问题:在textView中输入的文本位于文本视图区域的顶部,直到文本进入第二行,此时它跳转到键盘正上方的行,然后在添加新行时向上滚动。但我希望文本保留在textview的顶部,直到文本到达键盘上方的行,然后向上滚动。我无法弄清楚如何解决这个问题。

我花了一些时间搜索,但没有找到一个简单的例子。任何建议表示赞赏。

1 个答案:

答案 0 :(得分:0)

最后,我下载了Apple Keyboard Accessory应用程序,并将我的代码更改为匹配,现在可以使用了。 这是工作代码 - 但它不是一个优雅的代码的例子,因为我是一个业余爱好者:

#import "CREWGenericNotesVC.h"

@interface CREWGenericNotesVC ()

@property (nonatomic, weak) IBOutlet UIBarButtonItem *doneButton;
@property (nonatomic, weak) IBOutlet UITextView *textView;
// the height constraint we want to change when the keyboard shows/hides
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *constraintToAdjust; 

// @property(nonatomic) CGSize contentSize;

@end

@implementation CREWGenericNotesVC

#define VIEW_NAME @"CREWGenericNotesVC" // need the name of the view that calls this
#define VIEW_DESCRIPTION @"Generic notes"
#define RETURN_NC @"NCEmergencyKitsList" // where to return to when complete processing 

- (void)viewDidLoad {

[super viewDidLoad];

//    [_textView addObserver:self forKeyPath:@"contentSize" options:  (NSKeyValueObservingOptionNew) context:NULL];

// load saved notes into textView

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];


self.navigationItem.title = [defaults objectForKey:@"VCtitle"];
self.navigationItem.rightBarButtonItem = self.doneButton;

[self initializeView];

}

// create and load entity and notes
- (void) initializeView
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSString *viewName = [defaults objectForKey:@"VCname"]; // parameter to specify which view is calling notes and
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];

NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Notes" inManagedObjectContext:context];

NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];

NSPredicate *pred = [NSPredicate predicateWithFormat:@"(viewName = %@)", VIEW_NAME];
[request setPredicate:pred];

NSError *error = nil;
NSArray * objects = [context executeFetchRequest:request error:&error];

if ([objects count] == 0) { // create new notes instance if not already created
    [self newNotes:viewName]; //  create a new empty note object
} else {
    self.textView.text = [self getNotes:viewName];  //  load existing notes
}
} // end of initializeView

// create a new empty Notes record
- (void) newNotes:(NSString*)viewName
{
NSError *error = nil;
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];

NSManagedObject * newNotes;

newNotes = [NSEntityDescription insertNewObjectForEntityForName:@"Notes" inManagedObjectContext:context];

[newNotes setValue:viewName forKey:@"viewName"];
[newNotes setValue:nil forKey:@"viewNotes"];

if (! [context save:&error])
    NSLog(@"newNotes Couldn't save new data! Error:%@", [error description]); 
} // end of newNotes

// read existing notes
- (NSString*) getNotes:(NSString*)viewName// get stored notes
{
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];

NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Notes" inManagedObjectContext:context];

NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];

NSPredicate *pred = [NSPredicate predicateWithFormat:@"(viewName = %@)", viewName];
[request setPredicate:pred];

// Execute Fetch Request
NSManagedObjectContext * matches = nil;
NSError *fetchError = nil;
NSArray *objects = [appDelegate.managedObjectContext executeFetchRequest:request error:&fetchError];
if (fetchError) {
    NSLog(@"getNotes Fetch error:%@", fetchError); 
};

NSString *viewNotes;

if (! [objects count] == 0) {
    matches = objects [0];
    viewNotes = [matches valueForKey : @"viewNotes"];
}
return viewNotes;
} // end of getNotes

- (void)saveNotes:(NSString*)viewName toValue:(NSString*)newNotes // to get stored notes and update them
{
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];

NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Notes" inManagedObjectContext:context]; // get notes entity

NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];

NSPredicate *pred = [NSPredicate predicateWithFormat:@"(viewName = %@)", viewName ];
[request setPredicate:pred];

NSManagedObject *matches = nil;
NSError *error = nil;
NSArray * objects = [context executeFetchRequest:request error:&error];

if (![objects count] == 0) {
    matches = objects[0];
}
[matches setValue:newNotes forKey:@"viewNotes"];

if (! [context save:&error]) NSLog(@"newNotes Couldn't save notes! Error:%@", [error description]);
} // end of saveSwitch

// keyboard stuff

- (void)viewDidAppear:(BOOL)animated {

// observe keyboard hide and show notifications to resize the text view appropriately
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

// start editing the UITextView (makes the keyboard appear when the application launches)
[self editAction:self];
}

- (void)viewDidDisappear:(BOOL)animated {

[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:UIKeyboardWillChangeFrameNotification
                                              object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:UIKeyboardWillHideNotification
                                              object:nil];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[self adjustSelection:self.textView];
}

#pragma mark - Actions

- (IBAction)doneAction:(id)sender  {

// user tapped the Done button, release first responder on the text view
[self.textView resignFirstResponder];

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSString *viewName = [defaults objectForKey:@"VCname"]; // parameter to specify where to save notes
//    NSString *stringNC = [defaults objectForKey:@"NCname"]; // parameter to specify which navigation controller to return to
[self saveNotes:viewName toValue: self.textView.text]; // save notes

[defaults stringForKey:@"NCname"];
UIViewController *viewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:[defaults stringForKey:@"NCname"]]; 
[self presentViewController:viewController animated:YES completion:nil];
}

- (IBAction)editAction:(id)sender {

// user tapped the Edit button, make the text view first responder
[self.textView becomeFirstResponder];
}

#pragma mark - UITextViewDelegate

- (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView {
}

self.navigationItem.rightBarButtonItem = self.doneButton;

return YES;
}

- (BOOL)textViewShouldEndEditing:(UITextView *)aTextView {

[aTextView resignFirstResponder];

return YES;
}

- (void)adjustSelection:(UITextView *)textView {

// workaround to UITextView bug, text at the very bottom is slightly cropped by the keyboard
if ([textView respondsToSelector:@selector(textContainerInset)]) {
    [textView layoutIfNeeded];
    CGRect caretRect = [textView caretRectForPosition:textView.selectedTextRange.end];
    caretRect.size.height += textView.textContainerInset.bottom;
    [textView scrollRectToVisible:caretRect animated:NO];
}
}

- (void)textViewDidBeginEditing:(UITextView *)textView {

[self adjustSelection:textView];
}

- (void)textViewDidChangeSelection:(UITextView *)textView {

[self adjustSelection:textView];
}


#pragma mark - Responding to keyboard events

- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {

/*
 Reduce the size of the text view so that it's not obscured by the keyboard.
 Animate the resize so that it's in sync with the appearance of the keyboard.
 */

// transform the UIViewAnimationCurve to a UIViewAnimationOptions mask
UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
if (animationCurve == UIViewAnimationCurveEaseIn) {
    animationOptions |= UIViewAnimationOptionCurveEaseIn;
}
else if (animationCurve == UIViewAnimationCurveEaseInOut) {
    animationOptions |= UIViewAnimationOptionCurveEaseInOut;
}
else if (animationCurve == UIViewAnimationCurveEaseOut) {
    animationOptions |= UIViewAnimationOptionCurveEaseOut;
}
else if (animationCurve == UIViewAnimationCurveLinear) {
    animationOptions |= UIViewAnimationOptionCurveLinear;
}

[self.textView setNeedsUpdateConstraints];

if (showKeyboard) {
    UIDeviceOrientation orientation = self.interfaceOrientation;
    BOOL isPortrait = UIDeviceOrientationIsPortrait(orientation);

    NSValue *keyboardFrameVal = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardFrame = [keyboardFrameVal CGRectValue];
    CGFloat height = isPortrait ? keyboardFrame.size.height : keyboardFrame.size.width;

    // adjust the constraint constant to include the keyboard's height
    self.constraintToAdjust.constant += height;
}
else {
    self.constraintToAdjust.constant = 0;
}

NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

[UIView animateWithDuration:animationDuration delay:0 options:animationOptions animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

// now that the frame has changed, move to the selection or point of edit
NSRange selectedRange = self.textView.selectedRange;
[self.textView scrollRangeToVisible:selectedRange];
}

- (void)keyboardWillShow:(NSNotification *)notification {

/*
 Reduce the size of the text view so that it's not obscured by the keyboard.
 Animate the resize so that it's in sync with the appearance of the keyboard.
 */

NSDictionary *userInfo = [notification userInfo];
[self adjustTextViewByKeyboardState:YES keyboardInfo:userInfo];
}

- (void)keyboardWillHide:(NSNotification *)notification {

/*
 Restore the size of the text view (fill self's view).
 Animate the resize so that it's in sync with the disappearance of the keyboard.
 */

NSDictionary *userInfo = [notification userInfo];
[self adjustTextViewByKeyboardState:NO keyboardInfo:userInfo];
}

@end