如何在 iOS 7 上模拟键盘动画以将“完成”按钮添加到数字键盘?
Posted
技术标签:
【中文标题】如何在 iOS 7 上模拟键盘动画以将“完成”按钮添加到数字键盘?【英文标题】:How to mimic Keyboard animation on iOS 7 to add "Done" button to numeric keyboard? 【发布时间】:2013-09-21 03:25:54 【问题描述】:我一直在做类似的事情来模仿旧版本 ios 上的键盘动画。
CGRect keyboardBeginFrame;
[[note.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBeginFrame];
self.doneKeyboardButton.frame = CGRectMake(0, (keyboardBeginFrame.origin.y + keyboardBeginFrame.size.height) - 53, 106, 53);
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:self.doneKeyboardButton];
CGPoint newCenter = CGPointMake(self.doneKeyboardButton.superview.frame.origin.x + self.doneKeyboardButton.frame.size.width/2,
self.doneKeyboardButton.superview.frame.size.height - self.doneKeyboardButton.frame.size.height/2);
[UIView animateWithDuration:[[note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]-.02
delay:.0
options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]
animations:^
self.contentView.frame = CGRectOffset(self.contentView.frame, 0, -TextFieldViewMovement);
self.doneKeyboardButton.center = newCenter;
completion:nil];
但是,这已停止在 iOS7 上运行。返回的值似乎不再完全正确,并且“完成”按钮不再完全模仿键盘显示动画。
【问题讨论】:
我在您选择答案时尝试了该方法。但我不知道你是如何设置框架的。 尤其是 self.contentview.frame。 【参考方案1】:在 iOS 7 中,键盘使用了一种新的、未记录的动画曲线。虽然有些人注意到对动画选项使用未记录的值是可行的,但我更喜欢使用以下内容:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
// work
[UIView commitAnimations];
虽然建议使用基于块的动画,但从键盘通知返回的动画曲线是 UIViewAnimationCurve
,而您需要传递给基于块的动画的选项是 UIViewAnimationOptions
。使用传统的 UIView 动画方法,您可以直接将值通过管道输入。最重要的是,这将使用新的未记录动画曲线(整数值 7)并使动画与键盘匹配。而且,它同样适用于 iOS 6 和 7。
【讨论】:
简单!强壮的!天才!这个解决方案还让我摆脱了我的AACViewAnimationOptionsFromCurve
函数。
刚刚用这种旧样式替换了我所有的键盘动画块。感觉像是退后一步,但它确实有效。期待一旦 Apple 意识到自己的错误,就会回到区块链上。
我读到你可以简单地将曲线值移动 16 来获得选项值。 options = curve << 16;
但不管怎样,它都不适合我。
@Brennan 使用 UIViewAnimationCurve curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]
获得曲线并使用像 UIView animateWithDuration:duration delay:delay options:(curve << 16) animations:
这样的块动画 - 希望对您有所帮助。
把它翻译成 Swift 很简单,除了曲线参数需要这点丑陋:var curve:UIViewAnimationCurve = UIViewAnimationCurve(rawValue: info[UIKeyboardAnimationCurveUserInfoKey]!.integerValue)!
。【参考方案2】:
我遇到了同样的问题,并设法让动画在 iOS 7 中使用以下参数:
[UIView animateWithDuration:0.5
delay:0
usingSpringWithDamping:500.0f
initialSpringVelocity:0.0f
options:UIViewAnimationOptionCurveLinear
animations:animBlock
completion:completionBlock];
编辑:这些值是通过调试获得的,可以随着新的 iOS 版本而改变。 @DavidBeck's answer 在 iOS 7 中也适用于我,所以我在这里链接它。
【讨论】:
我将您标记为正确,因为我原来的解决方案不是很稳定。 @DavidBeck's answer 更好,因为它简单,理论上完美且稳定(向后和向前兼容),而此答案中使用的参数可能不准确,即使它们非常适合 iOS 7.0(如@Sabobin commented),对于其他版本的iOS,它们可能已关闭。例如,我很确定它们对于 iOS 是关闭的。 完美,帮了我这么多+1【参考方案3】:Apple 在 iOS 7 中使用了一些值为 7 的未记录动画。
但是UIViewAnimationCurve
的声明定义了 0 到 3 的值
typedef enum
UIViewAnimationCurveEaseInOut, // 0
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear // 3
UIViewAnimationCurve;
基于块的动画所需的UIViewAnimationOptions
定义为
enum
// ...
UIViewAnimationOptionCurveEaseInOut = 0 << 16,
UIViewAnimationOptionCurveEaseIn = 1 << 16,
UIViewAnimationOptionCurveEaseOut = 2 << 16,
UIViewAnimationOptionCurveLinear = 3 << 16,
UIViewAnimationOptionTransitionNone = 0 << 20,
// ...
;
Apple 似乎为动画曲线 (20 - 16 = 4) 保留了 4 位,它允许从 0 到 15 的值(因此可能有更多未记录的值)。
有了这些知识,您可以简单地将UIViewAnimationCurve
转换为UIViewAnimationOptions
,只需将其移动大约 16 位即可。在您的示例中,这意味着:
options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
【讨论】:
我确定您的意思是 4 位。 :) 这种方法仍然将枚举的值硬编码到程序的逻辑中。从我的角度来看不好,非常不面向 OO。【参考方案4】:您可以使用animateWithDuration
块并在其中设置曲线。它很干净而且工作得很好。
UIViewAnimationCurve curve = [[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
double duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
[UIView setAnimationCurve:curve];
/* ANIMATION HERE */
// don't forget layoutIfNeeded if you use autolayout
completion:nil];
编码愉快!
更新
你可以使用我写的一个简单的UIViewController类https://github.com/Just-/UIViewController-KeyboardAnimation
【讨论】:
【参考方案5】:如果您想在工具栏中添加按钮(类似于移动版 Safari),您可以使用属性 inputAccessoryView
(UITextField
和 UITextView
都有),省去所有麻烦.这个隐藏的宝石鲜为人知,我很高兴我偶然发现了它。
它适用于 iOS 6 和 iOS 7,我在我的应用程序 Routie 中使用它。
【讨论】:
不错的主意,但这个问题更多地集中在如何在数字键盘中未使用的按钮空间内实际添加覆盖按钮。 啊,好的。我认为这意味着按钮将位于键盘上方。究竟应该在哪里添加?左下角?我不知道,这似乎很不寻常。但也许我可以帮忙,因为我要自己创建整个键盘(我需要 . 和 - 那里),然后把它放在 GitHub 上。【参考方案6】:这对我来说很好用...显示键盘时会捕获持续时间。我知道硬编码选项意味着它可能会在未来中断,但它适用于 7 和 8。这对我们现在来说已经足够了......
[UIView animateWithDuration:self.animationDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^
[self.view layoutIfNeeded]; completion:^(BOOL finished)
if (finished)
if (completion)
completion();
];
【讨论】:
其实,在考虑了大约-3秒之后,我选择了安东的答案。【参考方案7】:iOS 10+Swift 5
更现代的替代方案(iOS 10+ 和 Swift)是使用 UIViewPropertyAnimator
,它不仅接受 UIView.AnimationCurve
,而且是更现代的动画师。
您很可能会使用UIResponder.keyboardAnimationCurveUserInfoKey
,我们将其视为NSNumber
。此密钥的文档是(Apple 自己的符号,不是我的):
public class let keyboardAnimationCurveUserInfoKey: String // NSNumber of NSUInteger (UIViewAnimationCurve)
使用这种方法,我们可以消除任何猜测,即插即用:
if let kbDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber,
let kbTiming = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber, // doc says to treat as NSNumber
let timing = UIView.AnimationCurve.RawValue(exactly: kbTiming), // takes an NSNumber
let curve = UIView.AnimationCurve(rawValue: timing) // takes a raw value
let duration = kbDuration.doubleValue
let animator = UIViewPropertyAnimator(duration: duration, curve: curve)
// add animations
animator.startAnimation()
【讨论】:
以上是关于如何在 iOS 7 上模拟键盘动画以将“完成”按钮添加到数字键盘?的主要内容,如果未能解决你的问题,请参考以下文章
文本字段的动画不隐藏在键盘下方,在 IOS 7 中的模拟器和实际设备中的行为不同