Я много искал код, который изменяет размер представления таблицы, чтобы вмещать клавиатуру, отображающую и скрывающуюся, но почти каждый столбец, который я натолкнулся, предполагает, что представление таблицы принимает весь вид своего контроллера представления. У меня есть iPad-приложение, в котором вид таблицы принимает только часть экрана. Какой правильный способ изменить размер представления таблицы в этом случае? (весь код в сообщениях, о которых я упоминал выше, не работает)
Алгоритм изменения размера клавиатуры UITableView
Ответ 1
Следующий код делает то, что вы хотите, и работает с любым устройством и любым макетом. Код предоставлен с помощью разумной системы TableView (с разрешения на копирование и использование).
- (void)keyboardWillShow:(NSNotification *)aNotification
{
if(keyboardShown)
return;
keyboardShown = YES;
// Get the keyboard size
UIScrollView *tableView;
if([self.tableView.superview isKindOfClass:[UIScrollView class]])
tableView = (UIScrollView *)self.tableView.superview;
else
tableView = self.tableView;
NSDictionary *userInfo = [aNotification userInfo];
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil];
// Get the keyboard animation details
NSTimeInterval animationDuration;
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
UIViewAnimationCurve animationCurve;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
// Determine how much overlap exists between tableView and the keyboard
CGRect tableFrame = tableView.frame;
CGFloat tableLowerYCoord = tableFrame.origin.y + tableFrame.size.height;
keyboardOverlap = tableLowerYCoord - keyboardRect.origin.y;
if(self.inputAccessoryView && keyboardOverlap>0)
{
CGFloat accessoryHeight = self.inputAccessoryView.frame.size.height;
keyboardOverlap -= accessoryHeight;
tableView.contentInset = UIEdgeInsetsMake(0, 0, accessoryHeight, 0);
tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, accessoryHeight, 0);
}
if(keyboardOverlap < 0)
keyboardOverlap = 0;
if(keyboardOverlap != 0)
{
tableFrame.size.height -= keyboardOverlap;
NSTimeInterval delay = 0;
if(keyboardRect.size.height)
{
delay = (1 - keyboardOverlap/keyboardRect.size.height)*animationDuration;
animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height;
}
[UIView animateWithDuration:animationDuration delay:delay
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{ tableView.frame = tableFrame; }
completion:^(BOOL finished){ [self tableAnimationEnded:nil finished:nil contextInfo:nil]; }];
}
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
if(!keyboardShown)
return;
keyboardShown = NO;
UIScrollView *tableView;
if([self.tableView.superview isKindOfClass:[UIScrollView class]])
tableView = (UIScrollView *)self.tableView.superview;
else
tableView = self.tableView;
if(self.inputAccessoryView)
{
tableView.contentInset = UIEdgeInsetsZero;
tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
if(keyboardOverlap == 0)
return;
// Get the size & animation details of the keyboard
NSDictionary *userInfo = [aNotification userInfo];
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil];
NSTimeInterval animationDuration;
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
UIViewAnimationCurve animationCurve;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
CGRect tableFrame = tableView.frame;
tableFrame.size.height += keyboardOverlap;
if(keyboardRect.size.height)
animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height;
[UIView animateWithDuration:animationDuration delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{ tableView.frame = tableFrame; }
completion:nil];
}
- (void) tableAnimationEnded:(NSString*)animationID finished:(NSNumber *)finished contextInfo:(void *)context
{
// Scroll to the active cell
if(self.activeCellIndexPath)
{
[self.tableView scrollToRowAtIndexPath:self.activeCellIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
[self.tableView selectRowAtIndexPath:self.activeCellIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
Примечания:
а. Вышеуказанные два метода были добавлены в центр уведомлений с использованием следующего кода:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
б. Иварцы, используемые выше, были объявлены следующим образом:
BOOL keyboardShown;
CGFloat keyboardOverlap;
с. 'self.activeCellIndexPath' всегда устанавливается в indexPath ячейки, владеющей текущим активным UITextField/UITextView.
Наслаждайтесь!:)
Ответ 2
Я нашел самое легкое решение для этого (я не поклонник использования subviews для такого рода вещей):
зарегистрироваться для уведомления об изменении рамки клавиатуры (идеальный регистр в viewWillAppear: и отменить регистрацию в viewWillDisappear:):
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
а затем в методе:
- (void)keyboardDidChangeFrame:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView];
kbIntersectFrame = CGRectIntersection(self.bounds, kbIntersectFrame);
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
или если вы хотите избавиться от "прыжка" после изменения содержимого:
- (void)keyboardDidChangeFrame:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView];
kbIntersectFrame = CGRectIntersection(self.scrollView.bounds, kbIntersectFrame);
// get point before contentInset change
CGPoint pointBefore = self.scrollView.contentOffset;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// get point after contentInset change
CGPoint pointAfter = self.scrollView.contentOffset;
// avoid jump by settings contentOffset
self.scrollView.contentOffset = pointBefore;
// and now animate smoothly
[self.scrollView setContentOffset:pointAfter animated:YES];
}
Ответ 3
Простым решением является добавление моего расширения UIViewController+Keyboard.swift
в ваш проект, с одной строкой setupKeyboardNotifcationListenerForScrollView(tableView)
он автоматически изменит размер автоматически. Не нужно ничего подклассифицировать, просто расширение! Его открытый источник в SingleLineKeyboardResize
Ответ 4
Простое решение - зарегистрируйтесь, чтобы получать уведомления о клавиатуре в init или viewDidLoad с помощью:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
то при получении уведомления вы можете использовать данный прямоугольник клавиатуры, чтобы настроить рамку таблицыView:
- (void)keyboardWillShow:(NSNotification *)notification
{
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect newTableFrame = _myTableView.frame;
//Here make adjustments to the tableview frame based on the value in keyboard size
...
_myTableView.frame = newTableFrame;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
//Here change the table frame back to what it originally was.
}
Ответ 5
Проверьте этот проект, перетащите его и просто объявите tablview как тип TPKeyboardAvoidingTableView
Ответ 6
Вот метод клавиатуры:
func keyboardControl(notification: NSNotification, isShowing: Bool) {
var userInfo = notification.userInfo!
let keyboardRect = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.unsignedIntValue
let convertedFrame = self.view.convertRect(keyboardRect, fromView: nil)
let heightOffset = self.view.bounds.size.height - convertedFrame.origin.y
let options = UIViewAnimationOptions(rawValue: UInt(curve) << 16)
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue
//your UITableView bottom constrant
self.tableViewMarginBottomConstraint.constant = heightOffset
var contentInsets = UIEdgeInsetsZero
if isShowing {
contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardRect.size.height), 0.0)
}
UIView.animateWithDuration(
duration,
delay: 0,
options: options.union(.LayoutSubviews).union(.BeginFromCurrentState),
animations: {
self.listTableView.contentInset = contentInsets
self.listTableView.scrollIndicatorInsets = contentInsets
self.listTableView.scrollBottomToLastRow()
self.view.layoutIfNeeded()
},
completion: { bool in
})
}
Вот расширение UITableView:
extension UITableView {
func totalRows() -> Int {
var i = 0
var rowCount = 0
while i < self.numberOfSections {
rowCount += self.numberOfRowsInSection(i)
i++
}
return rowCount
}
var lastIndexPath: NSIndexPath {
get { return NSIndexPath(forRow: self.totalRows()-1, inSection: 0) }
}
func scrollBottomToLastRow() {
self.scrollToRowAtIndexPath(self.lastIndexPath, atScrollPosition: .Bottom, animated: false)
}
}
Ответ 7
Вы можете добиться того, что ищете, используя IQKeyboardManager, это библиотека без кодового словаря, вам просто нужно добавить ее в свой Подфильтр: pod 'IQKeyboardManager', и он будет передавать эффект прокрутки при отображении клавиатуры, даже если UITextField/UITextView не является частью scrollView/tableView.