Jak zmienić rozmiar UITextView na iOS, gdy pojawi się klawiatura?
Jest UITextView
wstawione do zakładki w UITabBarController
(na iPhonie).
- wypełnij
UITextView
wieloma liniami. - Pokaż klawiaturę do edycji tekstu.
UITextView
kursorem. Nie można edytować tekstu jako wyniku.
Jak rozwiązać problem ze wszystkimi urządzeniami mobilnymi Apple (z inną rozdzielczością ekranu)? Wielkie dzięki za pomoc!
10 answers
Najlepszy wynik osiągnął poniższy kod. Nie zapomnij również ustawić koloru tła na UIView
i umieścić UITextView
przed innymi kontrolkami z górnego ekranu (np. UITabBar).
Edycja tekstu na końcu nadal nie jest idealna. Możesz spróbować poprawić.
FirstViewController.h:
@interface FirstViewController : UIViewController {
IBOutlet UIBarButtonItem *buttonDone;
IBOutlet UITextView *textView;
UITabBarController* tabBarController; // set from superview in AppDelegate (MainWindow.xib)
}
@property (nonatomic, retain) UITabBarController* tabBarController;
FirstViewController.m:
@synthesize tabBarController;
- (void)viewDidAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
textView.frame = newFrame;
[UIView commitAnimations];
}
- (void)keyboardWillShown:(NSNotification*)aNotification
{
buttonDone.enabled = true;
[self moveTextViewForKeyboard:aNotification up:YES];
}
- (void)keyboardWillHide:(NSNotification*)aNotification
{
buttonDone.enabled = false;
[self moveTextViewForKeyboard:aNotification up:NO];
}
P. S. trudno jest kodować na iOS bez stackoverflow...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 12:41:16
Z automatycznym układem jest o wiele łatwiej (pod warunkiem, że rozumiesz automatyczny układ) obsługiwać:
Zamiast próbować zidentyfikować i zmienić rozmiar widoków, których to dotyczy, po prostu tworzysz ramkę nadrzędną dla całej zawartości widoku. Następnie, Jeśli pojawi się kbd, zmienisz rozmiar ramki, a jeśli odpowiednio skonfigurujesz ograniczenia, widok zmieni ładną aranżację wszystkich widoków potomnych. Nie ma potrzeby bawić się wieloma trudnymi do odczytania kodami.
W rzeczywistości, w podobne pytanie znalazłem link do tego doskonały tutorial o tej technice.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:33
Napotkałem kilka problemów, starając się, aby mój widok tekstowy przewijał i animował poprawnie zarówno dla iOS 7, jak i iOS 8, a także z nową funkcją QuickType. Na początku skupiałem się na animowaniu wstawek widoku przewijania, ale zachowanie różniło się między iOS 7 i 8 i nie mogło działać poprawnie dla obu.
Potem zdałem sobie sprawę, że mogę uprościć rzeczy, skupiając się na ramce i to działało dla mnie z dużo prostszym kodem. W skrócie:
- Zarejestruj się na
UIKeyboardDidChangeFrameNotification
(To powiadomi, gdy QuickType jest wyświetlany / Ukryty, jak również). - dowiedz się, ile miejsca w pionie potrzebujesz, aby zmienić ramkę widoku tekstowego.
- animowanie zmiany rozmiaru klatki.
Oto kod, który ilustruje powyższe:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrameWithNotification:) name:UIKeyboardDidChangeFrameNotification object:nil];
}
- (void)keyboardDidChangeFrameWithNotification:(NSNotification *)notification {
CGFloat keyboardVerticalIncrease = [self keyboardVerticalIncreaseForNotification:notification];
[self animateTextViewFrameForVerticalOffset:keyboardVerticalIncrease];
}
- (CGFloat)keyboardVerticalIncreaseForNotification:(NSNotification *)notification {
CGFloat keyboardBeginY = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin.y;
CGFloat keyboardEndY = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
CGFloat keyboardVerticalIncrease = keyboardBeginY - keyboardEndY;
return keyboardVerticalIncrease;
}
- (void)animateTextViewFrameForVerticalOffset:(CGFloat)offset {
CGFloat constant = self.bottomConstraint.constant;
CGFloat newConstant = constant + offset;
self.bottomConstraint.constant = newConstant;
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
Krótka notka o animacji. Użyłem Autolayout, więc zdecydowałem się animować NSAutoLayoutConstraint widoku tekstowego, a nie ramkę bezpośrednio. W tym celu wywołuję [self.view layoutIfNeeded]
przed i wewnątrz bloku animacji. To jest prawidłowym sposobem animowania ograniczeń. Znalazłem tę wskazówkę tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:19
Warto zauważyć, że upvoted odpowiedź działa tylko wtedy, gdy urządzenie jest w trybie portretowym (a nie do góry nogami), w innych trybach granice idą źle. Wierzę, że można to uporządkować za pomocą ograniczeń, aby naprawić, ale nie mogłem tego zrobić, więc poniższa korekta zadziałała dla mnie: {]}
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.view.frame;
if (keyboardEndFrame.size.height >keyboardEndFrame.size.width)
{ //we must be in landscape
if (keyboardEndFrame.origin.x==0)
{ //upside down so need to flip origin
newFrame.origin = CGPointMake(keyboardEndFrame.size.width, 0);
}
newFrame.size.width -= keyboardEndFrame.size.width * (up?1:-1);
} else
{ //in portrait
if (keyboardEndFrame.origin.y==0)
{
//upside down so need to flip origin
newFrame.origin = CGPointMake(0, keyboardEndFrame.size.height);
}
newFrame.size.height -= keyboardEndFrame.size.height * (up?1:-1);
}
self.view.frame = newFrame;
[UIView commitAnimations];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-24 02:02:05
Najpierw dodaj kilka metod klawiatury do NSNotificationCenter
defaultCenter
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
Wtedy możesz zmienić rozmiary:
- (void)keyboardWillShow:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 187)]; //Or where ever you want the view to go
}
- (void)keyboardWillHide:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 324)]; //return it to its original position
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 12:41:26
- (void)registerKeyboardNotifications
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)unregisterKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void) keyboardWillHide:(NSNotification *)note
{
//adjust frame
}
-(void) keyboardWillShow:(NSNotification *)note
{
//adjust frame
}
I niezarejestrowanie zgłoszenia również w dealloc
- (void)unregisterKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 11:31:40
Lata minęły, pytanie jest wciąż aktualne. Apple zdecydowanie powinno zająć się tymi wszystkimi rzeczami sam. Ale tak nie jest. oto nowe rozwiązanie oparte na oficjalnej dokumentacji Apple plus poprawki błędów. Obsługuje iOS 8, ios 9, inputAccessoryView i jest gotowy do nowych wersji iOS i nowych urządzeń.
/* Apple's solution to resize keyboard but with accessory view support */
- (void)keyboardDidShow:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
editor.contentInset = contentInsets;
editor.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
editor.contentInset = contentInsets;
editor.scrollIndicatorInsets = contentInsets;
// button to hide the keyboard
buttonDone.enabled = false;
}
/* Fix issues with size classes and accessory view */
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// fix incorrect size of the inputAccessoryView when size class changed
// willTransitionToTraitCollection and traitCollectionDidChange can't help us
if (editor && editor.inputAccessoryView && !editor.inputAccessoryView.hidden) {
[editor resignFirstResponder];
}
}
/* Hide accessory view if a hardware keyboard is present */
#define gThresholdForHardwareKeyboardToolbar 160.f // it's minimum height of the software keyboard on iPhone 4 in landscape mode
- (bool)isExternalKeyboard:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;
return keyboardHeight < gThresholdForHardwareKeyboardToolbar;
}
- (void)keyboardWillShow:(NSNotification*)aNotification {
if ([self isExternalKeyboard:aNotification]) {
// hardware keyboard is present
if (editor && editor.inputAccessoryView) {
editor.inputAccessoryView.hidden = true;
}
} else {
// only on-screen keyboard
if (editor && editor.inputAccessoryView) {
editor.inputAccessoryView.hidden = false;
}
}
// button to hide the keyboard
buttonDone.enabled = true;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 22:18:51
Krótko mówiąc, zarejestruj powiadomienie klawiatury i wykonaj zmianę rozmiaru, gdy zostaniesz powiadomiony.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-24 02:19:32
Jako kontynuację, Technika, w której aktualizujesz ramkę, gdy pojawi się powiadomienie z klawiatury, nie działa w systemie iOS 7. Dla alternatywnego rozwiązania Patrz:
Jak zmienić rozmiar UITextView po wyświetleniu klawiatury w systemie iOS 7
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:32:41
Próbowałem znaleźć najlepszą odpowiedź tutaj jednak znalazłem w nim problem. Jeśli masz inne pole tekstowe na tej samej stronie, kliknij pole tekstowe, Pokaż klawiaturę. Zauważysz, że widok tekstu kurczy się. Jeśli jednak KLIKNIESZ teraz Widok tekstowy, zauważysz, że rozmiar widoku tekstowego zmniejszy się ponownie, podczas gdy nie powinien.
Moim rozwiązaniem tego problemu jest zachowanie właściwości kontrolera widoku reprezentującej stan klawiatury (pokazany/Ukryty). Jeśli klawiatura jest aktualnie widoczna, widok tekstowy powinien nie bądź skurczony. Jeśli używasz klawiatur o różnych rozmiarach dla różnych wejść tekstowych, należy również zachować stary rozmiar klawiatury.
Należy pamiętać, że rozwiązanie to również nie uwzględniało innej orientacji, co może mieć wpływ na sposób obliczania rozmiaru widoku tekstowego.
@implementation MyViewController {
BOOL keyboardShown;
NSInteger keyboardHeight;
}
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
NSInteger oldHeight = self->keyboardShown ? self->keyboardHeight : 0;
NSInteger newHeight = up ? keyboardFrame.size.height : 0;
NSInteger change = oldHeight - newHeight;
self->keyboardShown = up;
self->keyboardHeight = keyboardFrame.size.height;
newFrame.size.height += change;
self.textView.frame = newFrame;
[UIView commitAnimations];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-23 17:13:21