相对新手问题:在textView中输入的文本位于文本视图区域的顶部,直到文本进入第二行,此时它跳转到键盘正上方的行,然后在添加新行时向上滚动。但我希望文本保留在textview的顶部,直到文本到达键盘上方的行,然后向上滚动。我无法弄清楚如何解决这个问题。
我花了一些时间搜索,但没有找到一个简单的例子。任何建议表示赞赏。
答案 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