![](/img/trans.png)
[英]Handling external keyboard presses without showing keyboard on screen on iOS app
[英]Keyboard handling just like in Messages app in iOS 7
我正在實現一個類似於Messages應用程序中發生的視圖,因此有一個視圖,UITextView附加到屏幕的底部,還有UITableView顯示主要內容。 當它被輕敲時,它會隨着鍵盤向上滑動,當鍵盤被解除時,它會滑回到屏幕的底部。
我有這個部分並且它完美地工作 - 我只是訂閱鍵盤通知 - 將隱藏和顯示。
問題是我已經在UITableView上將鍵盤解除模式設置為交互式,並且我無法在平移時捕獲對鍵盤的更改。
第二個問題是這個uitextview欄覆蓋了uitableview的某些部分。 如何解決這個問題? 我仍然希望uitableview像在消息應用程序中一樣“在”這個欄下面。
我在所有地方都使用AutoLayout。
任何幫助將不勝感激!
============
EDIT1:這是一些代碼:
查看層次結構如下:
視圖 - UITableView(這個將包含“消息”) - UIView(這個將滑動)
UITableView對父視圖的頂部,左側,右側和底部有約束,因此它填滿整個屏幕。 UIView對父視圖的左側,右側和底部有約束,因此它粘在底部 - 我通過調整約束的常量來移動它。
在ViewWillAppear方法中:
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.DidShowNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillChangeFrameNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, OnKeyboardWillHideNotification);
以下是方法:
void OnKeyboardDidShowNotification (NSNotification notification)
{
AdjustViewToKeyboard (Ui.KeyboardHeightFromNotification (notification), notification);
}
void OnKeyboardWillHideNotification (NSNotification notification)
{
AdjustViewToKeyboard (0.0f, notification);
}
void AdjustViewToKeyboard (float offset, NSNotification notification = null)
{
commentEditViewBottomConstraint.Constant = -offset;
if (notification != null) {
UIView.BeginAnimations (null, IntPtr.Zero);
UIView.SetAnimationDuration (Ui.KeyboardAnimationDurationFromNotification (notification));
UIView.SetAnimationCurve ((UIViewAnimationCurve)Ui.KeyboardAnimationCurveFromNotification (notification));
UIView.SetAnimationBeginsFromCurrentState (true);
}
View.LayoutIfNeeded ();
commentEditView.LayoutIfNeeded ();
var insets = commentsListView.ContentInset;
insets.Bottom = offset;
commentsListView.ContentInset = insets;
if (notification != null) {
UIView.CommitAnimations ();
}
}
我建議您覆蓋視圖控制器的-inputAccessoryView屬性,並將可編輯的UITextView作為其子視圖。 另外,不要忘記覆蓋-canBecomeFirstResponder方法以返回YES。
- (BOOL)canBecomeFirstResponder
{
if (!RUNNING_ON_IOS7 && !RUNNING_ON_IPAD)
{
//Workaround for iOS6-specific bug
return !(self.viewDisappearing) && (!self.viewAppearing);
}
return !(self.viewDisappearing);
}
通過這種方法,系統管理一切。
還有一些你必須了解的解決方法:對於UISplitViewController( UISplitViewController僅詳細信息的inputAccessoryView ),用於釋放錯誤( UIViewController,而inputAccessoryView沒有被釋放 )等等。
該解決方案基於SO的許多不同答案。 它有很多好處:
UITableView
上進行交互式手勢時,鍵盤跟隨鍵盤 UITableViewCell
從下到上,就像在消息應用程序中一樣 UITableViewCell
這段代碼正常工作:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = // . . .
// . . .
cell.contentView.transform = CGAffineTransformMakeScale(1,-1);
cell.accessoryView.transform = CGAffineTransformMakeScale(1,-1);
return cell;
}
- (UIView *)inputAccessoryView {
return self.composeBar;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.transform = CGAffineTransformMakeScale(1,-1);
// This code prevent bottom inset animation while appearing view
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
newEdgeInsets.top = CGRectGetMaxY(self.navigationController.navigationBar.frame);
newEdgeInsets.bottom = self.view.bounds.size.height - self.composeBar.frame.origin.y;
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
self.tableView.contentOffset = CGPointMake(0, -newEdgeInsets.bottom);
// This code need to be done if you added compose bar via IB
self.composeBar.delegate = self;
[self.composeBar removeFromSuperview];
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:nil usingBlock:^(NSNotification *note)
{
NSNumber *duration = note.userInfo[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *options = note.userInfo[UIKeyboardAnimationCurveUserInfoKey];
CGRect beginFrame = [note.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect endFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
newEdgeInsets.bottom = self.view.bounds.size.height - endFrame.origin.y;
CGPoint newContentOffset = self.tableView.contentOffset;
newContentOffset.y += endFrame.origin.y - beginFrame.origin.y;
[UIView animateWithDuration:duration.doubleValue
delay:0.0
options:options.integerValue << 16
animations:^{
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
self.tableView.contentOffset = newContentOffset;
} completion:^(BOOL finished) {
;
}];
}];
}
例如使用pod 'PHFComposeBarView'
撰寫欄:
@property (nonatomic, strong) IBOutlet PHFComposeBarView *composeBar;
並將此類用於表視圖:
@interface InverseTableView : UITableView
@end
@implementation InverseTableView
void swapCGFLoat(CGFloat *a, CGFloat *b) {
CGFloat tmp = *a;
*a = *b;
*b = tmp;
}
- (UIEdgeInsets)contentInset {
UIEdgeInsets insets = [super contentInset];
swapCGFLoat(&insets.top, &insets.bottom);
return insets;
}
- (void)setContentInset:(UIEdgeInsets)contentInset {
swapCGFLoat(&contentInset.top, &contentInset.bottom);
[super setContentInset:contentInset];
}
@end
如果您希望通過點擊消息來消除鍵盤:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.composeBar.textView resignFirstResponder];
}
不要打電話給這個,這將隱藏composeBar
:
[self resignFirstResponder];
更新2:
鍵盤跟蹤的新解決方案效果更好:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Compose view height growing tracking
[self.composeBar addObserver:self forKeyPath:@"frame" options:0 context:nil];
// iOS 7 keyboard tracking
[self.composeBar.superview addObserver:self forKeyPath:@"center" options:0 context:nil];
// iOS 8 keyboard tracking
[self.composeBar.superview addObserver:self forKeyPath:@"frame" options:0 context:nil];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.composeBar removeObserver:self forKeyPath:@"frame"];
[self.composeBar.superview removeObserver:self forKeyPath:@"center"];
[self.composeBar.superview removeObserver:self forKeyPath:@"frame"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == self.composeBar.superview || object == self.composeBar)
{
// Get all values
CGPoint newContentOffset = self.tableView.contentOffset;
UIEdgeInsets newEdgeInsets = self.tableView.contentInset;
UIEdgeInsets newScrollIndicartorInsets = self.tableView.scrollIndicatorInsets;
// Update values
CGFloat bottomInset = self.view.bounds.size.height - [self.composeBar convertPoint:CGPointZero toView:self.view].y;
CGFloat diff = newEdgeInsets.bottom - (bottomInset + 7);
newContentOffset.y += diff;
newEdgeInsets.bottom = bottomInset + 7;
newScrollIndicartorInsets.bottom = bottomInset;
// Set all values
if (diff < 0 || diff > 40)
self.tableView.contentOffset = CGPointMake(0, newContentOffset.y);
self.tableView.contentInset = newEdgeInsets;
self.tableView.scrollIndicatorInsets = newEdgeInsets;
}
}
好的,交互式鍵盤解雇將發送名為UIKeyboardDidChangeFrameNotification
的通知。
這可用於在交互式解除鍵盤時移動文本視圖。
您已經在使用它,但是您將它發送到OnKeyboardDidShow
方法。
你需要一個名為keyboardFramedDidChange
的第三種方法。 這適用於皮革和秀。
對於第二個問題,你應該有這樣的垂直約束......
|[theTableView][theTextView (==44)]|
這會將tableview的底部綁定到文本視圖的頂部。
這不會改變任何動畫的工作方式,只是確保表視圖將顯示其所有內容,無論鍵盤是否可見。
不要更新表視圖的內容insets。 使用約束確保框架不重疊。
PS整理你的命名約定。 方法名稱以小寫字母開頭。
PPS使用基於塊的動畫。
我嘗試使用空的零高度inputAccessoryView
。 訣竅是當鍵盤出現時將文本字段的底部粘到它上面,這樣它們就可以一起移動。 鍵盤消失后,您可以破壞該約束並再次粘貼到屏幕底部。
我為此目的制作了一個開源庫。 它適用於iOS 7和8,並且也可以作為cocoapod使用。
https://github.com/oseparovic/MessageComposerView
以下是它的樣子:
您可以使用如下所示的非常基本的init
函數來創建屏幕寬度和默認高度,例如:
self.messageComposerView = [[MessageComposerView alloc] init];
self.messageComposerView.delegate = self;
[self.view addSubview:self.messageComposerView];
還有一些其他初始化程序可用於自定義框架,鍵盤偏移和textview最大高度以及一些代表以掛鈎框架更改和按鈕單擊。 請參閱自述文件了解更多!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.