经过大量的试验和错误,我放弃了,并提出了这个问题。我见过很多人有类似的问题,但不能得到所有的答案工作正确。
我有一个由自定义单元格组成的UITableView。单元格由相邻的5个文本字段组成(有点像网格)。
当我试图滚动和编辑UITableView底部的单元格时,我不能设法让我的单元格正确地定位在键盘上方。
我看到过很多关于改变视图大小的回答……但到目前为止,没有一种效果很好。
谁能用一个具体的代码示例来阐明这样做的“正确”方式?
经过大量的试验和错误,我放弃了,并提出了这个问题。我见过很多人有类似的问题,但不能得到所有的答案工作正确。
我有一个由自定义单元格组成的UITableView。单元格由相邻的5个文本字段组成(有点像网格)。
当我试图滚动和编辑UITableView底部的单元格时,我不能设法让我的单元格正确地定位在键盘上方。
我看到过很多关于改变视图大小的回答……但到目前为止,没有一种效果很好。
谁能用一个具体的代码示例来阐明这样做的“正确”方式?
当前回答
不需要任何计算,使用下面的代码,它将工作: 这段代码我用在我的自定义UITableviewcell,它是工作的:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}
func keyboardWillShow(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
}}
func keyboardWillHide(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}}
其他回答
因为你在一个表格中有文本字段,最好的方法是调整表格的大小——你需要设置tableView.frame的高度比键盘的大小小(我认为大约165像素),然后当键盘被关闭时再次展开它。
如果你不想让用户滚动,你也可以选择在那个时候禁用tableView的用户交互。
我在做一些非常相似的事情它是通用的,不需要为你的代码计算特定的东西。 只需检查代码上的注释:
在MyUIViewController.h
@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableView *myTableView;
UITextField *actifText;
}
@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;
-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;
@end
在MyUIViewController.m
@implementation MyUIViewController
@synthesize myTableView;
@synthesize actifText;
- (void)viewDidLoad
{
// Register notification when the keyboard will be show
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
// Register notification when the keyboard will be hide
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
// To be link with your TextField event "Editing Did Begin"
// memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
self.actifText = textField;
}
// To be link with your TextField event "Editing Did End"
// release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
self.actifText = nil;
}
-(void) keyboardWillShow:(NSNotification *)note
{
// Get the keyboard size
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];
// Detect orientation
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = self.myTableView.frame;
// Start animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// Reduce size of the Table view
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
frame.size.height -= keyboardBounds.size.height;
else
frame.size.height -= keyboardBounds.size.width;
// Apply new size of table view
self.myTableView.frame = frame;
// Scroll the table view to see the TextField just above the keyboard
if (self.actifText)
{
CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
[self.myTableView scrollRectToVisible:textFieldRect animated:NO];
}
[UIView commitAnimations];
}
-(void) keyboardWillHide:(NSNotification *)note
{
// Get the keyboard size
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];
// Detect orientation
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = self.myTableView.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// Increase size of the Table view
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
frame.size.height += keyboardBounds.size.height;
else
frame.size.height += keyboardBounds.size.width;
// Apply new size of table view
self.myTableView.frame = frame;
[UIView commitAnimations];
}
@end
Swift 1.2+版本:
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var activeText: UITextField!
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("keyboardWillShow:"),
name: UIKeyboardWillShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("keyboardWillHide:"),
name: UIKeyboardWillHideNotification,
object: nil)
}
func textFieldDidBeginEditing(textField: UITextField) {
activeText = textField
}
func textFieldDidEndEditing(textField: UITextField) {
activeText = nil
}
func keyboardWillShow(note: NSNotification) {
if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
var frame = tableView.frame
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.3)
frame.size.height -= keyboardSize.height
tableView.frame = frame
if activeText != nil {
let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
tableView.scrollRectToVisible(rect, animated: false)
}
UIView.commitAnimations()
}
}
func keyboardWillHide(note: NSNotification) {
if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
var frame = tableView.frame
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.3)
frame.size.height += keyboardSize.height
tableView.frame = frame
UIView.commitAnimations()
}
}
}
因此,经过数小时的艰苦工作,尝试使用这些当前的解决方案(完全失败),我终于让事情正常工作,并更新它们以使用新的动画块。我的回答完全基于Ortwin上面的回答。
所以不管出于什么原因,上面的代码就是不适合我。我的设置似乎和其他人的很相似,但可能是因为我用的是iPad或4.3……不知道。它在做一些古怪的数学运算然后把我的tableview从屏幕上拍下来。
见我的解决方案的最终结果:http://screencast.com/t/hjBCuRrPC(请忽略照片。: - p)
所以我沿用了Ortwin的基本原理,但改变了计算原点的方法。Y和尺寸。我的表格视图的高度和键盘的高度。当我从结果中减去窗口的高度时,它告诉我有多少交集。如果它大于0(也就是有一些重叠),我执行帧高度的动画。
此外,还有一些重绘问题得到了解决,1)等待滚动到单元格直到动画完成,2)使用UIViewAnimationOptionBeginFromCurrentState选项隐藏键盘。
有几件事需要注意。
_topmostrowbeforekeyboardwasshow & _originalFrame是在头文件中声明的实例变量。 自我。guestEntryTableView是我的tableView(我在外部文件中) iaskcgrecswap是Ortwin用于翻转帧坐标的方法 我只更新tableView的高度如果它至少有50px会显示 因为我不在UIViewController中,所以我没有self。视图,我只是把tableView返回到它的原始框架
同样,如果我Ortwin没有提供关键,我也不会得到这个答案。代码如下:
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
self.activeTextField = textField;
if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
_topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
} else {
// this should never happen
_topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
[textField resignFirstResponder];
}
}
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
self.activeTextField = nil;
}
- (void)keyboardWillShow:(NSNotification*)notification {
NSDictionary* userInfo = [notification userInfo];
NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Reduce the tableView height by the part of the keyboard that actually covers the tableView
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
windowRect = IASKCGRectSwap(windowRect);
viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
keyboardFrame = IASKCGRectSwap(keyboardFrame);
}
// fix the coordinates of our rect to have a top left origin 0,0
viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);
CGRect frame = self.guestEntryTableView.frame;
_originalFrame = self.guestEntryTableView.frame;
int remainder = (viewRectAbsolute.origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;
if (remainder > 0 && !(remainder > frame.size.height + 50)) {
frame.size.height = frame.size.height - remainder;
float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration: duration
animations:^{
self.guestEntryTableView.frame = frame;
}
completion:^(BOOL finished){
UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
[self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}];
}
}
- (void)keyboardWillHide:(NSNotification*)notification {
NSDictionary* userInfo = [notification userInfo];
float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration: duration
delay: 0.0
options: (UIViewAnimationOptionBeginFromCurrentState)
animations:^{
self.guestEntryTableView.frame = _originalFrame;
}
completion:^(BOOL finished){
[self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}];
}
#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
CGRect newRect;
newRect.origin.x = rect.origin.y;
newRect.origin.y = rect.origin.x;
newRect.size.width = rect.size.height;
newRect.size.height = rect.size.width;
return newRect;
}
CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
CGRect newRect;
switch(orientation)
{
case UIInterfaceOrientationLandscapeLeft:
newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), rect.origin.y, rect.size.width, rect.size.height);
break;
case UIInterfaceOrientationLandscapeRight:
newRect = CGRectMake(rect.origin.x, parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
break;
case UIInterfaceOrientationPortrait:
newRect = rect;
break;
case UIInterfaceOrientationPortraitUpsideDown:
newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
break;
}
return newRect;
}
以下是我如何做到这一点的,这是Sam Ho和Marcel W的回答,以及我自己对蹩脚代码的一些错误修复。我用的是UITableViewController。当键盘显示时,表格现在可以正确地调整大小。
1)在viewDidLoad我添加:
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
2)我忘记在viewWillAppear和awakeFromNib中调用超等价物。我把这些加回来了。
结合并填写几个答案(特别是Ortwin Gentz,用户98013)和另一篇文章中的空白,这将适用于iPad上的SDK 4.3的纵向或横向模式:
@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
if (self.isFirstResponder) {
return self;
}
for (UIView *subView in self.subviews) {
UIResponder *firstResponder = [subView findFirstResponder];
if (firstResponder != nil) {
return firstResponder;
}
}
return nil;
}
@end
@implementation MyViewController
- (UIResponder *)currentFirstResponder {
return [self.view findFirstResponder];
}
- (IBAction)editingEnded:sender {
[sender resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void)keyboardWillShow:(NSNotification*)notification {
if ([self currentFirstResponder] != nil) {
NSDictionary* userInfo = [notification userInfo];
// we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
if (!keyboardFrameValue) {
keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
}
// Reduce the tableView height by the part of the keyboard that actually covers the tableView
CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
CGRect frame = _tableView.frame;
if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
}
frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_tableView.frame = frame;
[UIView commitAnimations];
UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];
// iOS 3 sends hide and show notifications right after each other
// when switching between textFields, so cancel -scrollToOldPosition requests
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
[_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
- (void) scrollToOldPosition {
[_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void)keyboardWillHide:(NSNotification*)notification {
if ([self currentFirstResponder] != nil) {
NSDictionary* userInfo = [notification userInfo];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_tableView.frame = self.view.bounds;
[UIView commitAnimations];
[self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
}
}
@end