我有一个固定在键盘顶部的文本字段。我不能使用inputAccessoryView,因为它总是显示。我能够观察键盘隐藏/显示的通知,使用键盘上下移动它,但这似乎不适用于UIScrollViewKeyboardDismissModeInteractive。有没有办法获得键盘位置的持续反馈以同步动画?
答案 0 :(得分:17)
编辑:看起来这在iOS 8中不起作用,伙计们 - 对不起!我也在寻找新的解决方案
我通过创建一个不可见的inputAccessoryView来解决这个问题。
textView.inputAccessoryView = [[MJXObservingInputAccessoryView alloc] init];
accessoryView观察其超级视图的框架并发布您可以匹配的通知。
static NSString * const MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification = @"MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification";
@interface MJXObservingInputAccessoryView : UIView @end
@implementation MJXObservingInputAccessoryView
- (void)willMoveToSuperview:(UIView *)newSuperview
{
if (self.superview)
{
[self.superview removeObserver:self
forKeyPath:@"frame"];
}
[newSuperview addObserver:self
forKeyPath:@"frame"
options:0
context:NULL];
[super willMoveToSuperview:newSuperview];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (object == self.superview && [keyPath isEqualToString:@"frame"])
{
[[NSNotificationCenter defaultCenter] postNotificationName:MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification
object:self];
}
}
@end
答案 1 :(得分:9)
我找到了一个解决方案(虽然有点像黑客),我实现了scrollViewDidScroll来监听UITableView中内置的panGestureRecognizer。事实证明,键盘的顶部在整个手势中都能保持完美均匀,因此您可以不断更新文本字段,使其保持在平移手指上方。
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint fingerLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
CGPoint absoluteFingerLocation = [scrollView convertPoint:fingerLocation toView:self.view];
if (_keyboardIsOpen && scrollView.panGestureRecognizer.state == UIGestureRecognizerStateChanged && absoluteFingerLocation.y >= (self.view.frame.size.height - _keyboardFrame.size.height)) {
[UIView animateWithDuration:.05 animations:^{
//This is an autolayout constraint that needs to be set to the distance between the top of the keyboard and the bottom of the screen (with a buffer of 3)
_bottomViewVerticalSpacingConstraint.constant = [[UIScreen mainScreen] bounds].size.height - absoluteFingerLocation.y - 3;
[self.view layoutIfNeeded];
}];
}
}
然后我也注册了通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillChangeFrame:)
name:UIKeyboardWillChangeFrame object:nil];
并按照这样处理它们
-(void)keyboardWillShown:(NSNotification*)aNotification
{
_keyboardIsOpen = YES;
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:.05 animations:^{
_bottomViewVerticalSpacingConstraint.constant = kbSize.height;
[self.view layoutIfNeeded];
}];
}
-(void)keyboardWillBeHidden:(NSNotification*)aNotification
{
_keyboardIsOpen = NO;
[UIView animateWithDuration:.3 animations:^{
_bottomViewVerticalSpacingConstraint.constant = 0;
[self.view layoutIfNeeded];
}];
}
-(void)keyboardWillChangeFrame:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
_keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
}
答案 2 :(得分:7)
Malcolm的答案适用于iOS 8和7,只需稍作调整即可。我没有足够的声誉来评论他的帖子,所以这被添加为社区维基,供需要适用于iOS 7和8的解决方案的人使用。
标题
#import <UIKit/UIKit.h>
static NSString *const SSObservingInputAccessoryViewFrameDidChangeNotification = @"SSObservingInputAccessoryViewFrameDidChangeNotification";
@interface SSObservingInputAccessoryView : UIView
@end
实施
#import "SSObservingInputAccessoryView.h"
@implementation SSObservingInputAccessoryView
- (void)willMoveToSuperview:(UIView *)newSuperview {
if (self.superview) {
[self.superview removeObserver:self
forKeyPath:@"center"];
[self.superview removeObserver:self
forKeyPath:@"frame"];
}
[newSuperview addObserver:self
forKeyPath:@"center"
options:0
context:nil];
[newSuperview addObserver:self
forKeyPath:@"frame"
options:0
context:nil];
[super willMoveToSuperview:newSuperview];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self.superview
&& ([keyPath isEqualToString:@"center"] || [keyPath isEqualToString:@"frame"])) {
[[NSNotificationCenter defaultCenter] postNotificationName:SSObservingInputAccessoryViewFrameDidChangeNotification
object:self];
}
}
@end
答案 3 :(得分:1)
有一种更简单的方法可以将某些东西固定在键盘上。您只需要实现这些方法,iOS将为您处理它。
- (UIView *) inputAccessoryView {
// Return your textfield, buttons, etc
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
答案 4 :(得分:1)
只有在iPhone X iOS 11.2.2上的Swift 4交互式更新CALayer位置:
class MyValueObservingView: UIView {
static let CALayerPositionChangeNotification = Notification.Name("CALayerPositionChangeNotification")
static let CALayerPositionUserInfoKey = "position"
override func willMove(toSuperview newSuperview: UIView?) {
superview?.layer.removeObserver(self, forKeyPath: type(of: self).CALayerPositionUserInfoKey)
newSuperview?.layer.addObserver(self, forKeyPath: type(of: self).CALayerPositionUserInfoKey, options: [.initial, .new], context: nil)
super.willMove(toSuperview: newSuperview)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == type(of: self).CALayerPositionUserInfoKey, let position = change?[.newKey] as? CGPoint {
// print("MyValueObservingView layer position changed to \(position)")
NotificationCenter.default.post(name: type(of: self).CALayerPositionChangeNotification, object: self, userInfo: [type(of: self).CALayerPositionUserInfoKey: position])
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
}
答案 5 :(得分:0)
您是否尝试过DAKeyboardControl?
UIView *addCommentContainer = self.addCommentContainer;
[self.view addKeyboardPanningWithActionHandler:^(CGRect keyboardFrameInView) {
[addCommentContainer setY:keyboardFrameInView.origin.y - addCommentContainer.frame.size.height];
}];
您可以在此控件上看到处理键盘框架的源代码。
答案 6 :(得分:0)
JordanC的解决方案有很多问题,但可能适用于某些用例。我将该代码转换为下面的代码。
class MyViewController: UIViewController {
@IBOutlet var tableView: UITableView!
@IBOutlet var bottomViewVerticalSpacingConstraint: NSLayoutConstraint!
private(set) var keyboardIsOpen: Bool = false
private(set) var keyboardFrame: CGRect = .zero
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.keyboardDismissMode = .interactive
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
keyboardIsOpen = true
guard let userInfo = notification.userInfo else { return }
guard let keyboardSize = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size else { return }
UIView.animate(withDuration: 0.05) {
self.bottomViewVerticalSpacingConstraint.constant = keyboardSize.height
self.view.layoutIfNeeded()
}
}
@objc func keyboardWillHide(notification: NSNotification) {
keyboardIsOpen = false
UIView.animate(withDuration: 0.05) {
self.bottomViewVerticalSpacingConstraint.constant = 0
self.view.layoutIfNeeded()
}
}
@objc func keyboardWillChangeFrame(notification: NSNotification) {
keyboardIsOpen = false
guard let userInfo = notification.userInfo else { return }
guard let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
self.keyboardFrame = keyboardFrame
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let fingerLocation = scrollView.panGestureRecognizer.location(in: scrollView)
let absoluteFingerLocation = scrollView.convert(fingerLocation, to: self.view)
if keyboardIsOpen && scrollView.panGestureRecognizer.state == .changed && absoluteFingerLocation.y >= (self.view.frame.size.height - keyboardFrame.size.height) {
UIView.animate(withDuration: 0.05) {
self.bottomViewVerticalSpacingConstraint.constant = UIScreen.main.bounds.size.height - absoluteFingerLocation.y - 3
self.view.layoutIfNeeded()
}
}
}
}
答案 7 :(得分:-2)
这对我有用:
注册键盘确实隐藏了通知:UIKeyboardDidHideNotification
。
在viewDidLoad
中,使用addSubview
将工具栏添加到视图底部。
我使用textView,所以在textViewShouldBeginEditing
我设置了inputAccessoryView。
然后在键盘上做了隐藏方法,调整工具栏的框架,将inputAccessoryView设置为nil,重要的是,再次将工具栏添加为视图的子视图。