我已经创建了一个有4个字段和一个按钮的表单。视图层次结构如下所示: Main UIVIew,view (改名为contentView),在contentView之上,我有4个字段和一个以编程方式创建的按钮。
在此尝试之前,我将按钮放在ViewController视图上,将按钮的底部约束分配给一个变量,而当keyboardDidShow将键盘大小添加到底部约束时,就会将按钮放在键盘上方。然而,一个堆栈花说这种方法很容易出错:Move button when keyboard appears swift
我遵守了本教程,但我没有得到相同的结果。https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/
考虑到Iphone的屏幕大小不同,请给出最佳的解决方案。
class EleventhViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var fullName: UITextField!
@IBOutlet weak var flatNumber: UITextField!
@IBOutlet weak var streetAddress: UITextField!
@IBOutlet weak var phoneNumber: UITextField!
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var scrollView: UIScrollView!
var nextButtonOutlet:UIButton!
override func viewDidLoad() {
super.viewDidLoad()
//called whenever keyboard is shown/hidden
registerForKeyboardNotifications()
//when identifies single or multiple taps, call DismissKeyboard
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
contentView.addGestureRecognizer(tap)
//create button programmatically
var button = UIButton(type: UIButtonType.custom) as UIButton
button = UIButton(frame: CGRect(x: 0, y: 637, width: 375, height: 50))
button.titleLabel?.textColor = UIColor.white
button.backgroundColor = UIColor(colorLiteralRed: 117/255, green: 232/255, blue: 0, alpha: 1)
button.setTitle("Next", for: .normal)
button.addTarget(self, action: #selector(EleventhViewController.nextButton), for: .touchUpInside)
self.contentView.addSubview(button)
self.nextButtonOutlet = button
//disable scroll bouncing
scrollView.bounces = false
self.fullName.delegate = self
self.flatNumber.delegate = self
self.streetAddress.delegate = self
self.phoneNumber.delegate = self
}
//Call this function when the tap is recognized.
func DismissKeyboard(){
contentView.endEditing(true)
}
// Stop Editing on Return Key Tap.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
weak var activeField: UITextField?
func keyboardDidShow(_ notification: Notification) {
//when a textfield is edited lift the button above the keyboard
if let activeField = self.activeField,let keyboardSize =
(notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as?
NSValue)?.cgRectValue {
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom:
keyboardSize.height, right: 0.0)
self.scrollView.contentInset = contentInsets
var aRect = self.view.frame
aRect.size.height -= keyboardSize.size.height
if !aRect.contains(nextButtonOutlet.frame.origin) {
self.scrollView.scrollRectToVisible(nextButtonOutlet.frame, animated: true)
}
}
func keyboardWillHide(_ notification: Notification) {
let contentInsets = UIEdgeInsets.zero
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
}
//Keep track of which textfield is being edited to make sure the field is visible when keyboard pops up
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
self.activeField = nil
}
//register for keyboard notifications
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector:
#selector(keyboardDidShow),
name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector:
#selector(keyboardWillHide), name:
NSNotification.Name.UIKeyboardWillHide, object: nil)
}
//remove keyBoard observers
func deregisterFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name:
NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name:
NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
//deregister keyboard notifications
deregisterFromKeyboardNotifications()
}
} //end of class
view Hierachy
When viewDidLoad is triggered,button does not show
开始键入textFields时
When keyboard is hidden
Desired result
发布于 2017-03-03 13:32:32
因此,我认为您已经接近了,我不确定这是代码问题还是自动收费问题。我猜你正在收到关于你的滚动视图的抱怨,不知道内容大小,所以我将涵盖这两个方面。
编辑:另外,您的按钮必须位于我首先添加的视图容器下面,并且需要与滚动视图分开处理。不要把它放在滚动视图中。
这些方法在下面工作,除了将50或任何东西添加到包含滚动视图的视图的布局底部。另外,下面的方法将有助于编辑
Autolayout:首先,对于只在页面上使用的表单,我喜欢从添加一个视图开始,并在顶部布局指南(按钮所需的任何空间)中添加一个视图,左和右。然后,我将我的scrollview (将滚动视图引脚到该视图)添加到视图( added.Then )中,接下来,我将内容视图添加到滚动视图中。现在,我将其固定在滚动视图上。你会发现自动收费表仍然不快乐。那么为什么第一个视图和如何解决这个问题。我从contentView拖到保持滚动视图的视图,并选择等高和等宽。现在你不会有自动布局对你尖叫。注意:这适用于您想要填充第一个视图大小的内容,但允许它滚动以避免使用键盘。见图
在添加这个等高后,我可以继续使用故事板。我设置了文本框。底部的textfield,您可能想要也可能不想将它钉在底部,但是如果您确实这样做了,>= yourNumber。
编辑:现在将您的下一个按钮添加到包含所有内容的视图下面的情节提要中。必须将按钮固定在主视图的底部,然后用0来坚持键盘。现在看起来会是这样。
显然,这与初始图像略有冲突,但您所要做的只是增加底部布局指南的空间,只需确保将按钮添加到主视图,而不是保留滚动视图的视图。现在,将您的按钮连接到iboutlet中的控制器。我们需要它。
接下来,请确保模拟器中有正确的键盘。**不使用硬件键盘
最后是密码。其中有些您需要替换textfield变量,因为我在子视图中循环以设置委托。我还在卷轴上添加了填充。应该将deRegister移动到deint()。查看我的代码,最后您可能想滚动键盘上的滚动视图,而不是原来的显示,但是我没有改变这一点。
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
//added in storyboard. removed the code
@IBOutlet weak var nextButton: UIButton!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
//called whenever keyboard is shown/hidden
registerForKeyboardNotifications()
//when identifies single or multiple taps, call DismissKeyboard
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
contentView.addGestureRecognizer(tap)
//disable scroll bouncing
scrollView.bounces = false
//replace with your textfields
for subs in self.contentView.subviews{
if subs is UITextField{
print("setting")
(subs as! UITextField).delegate = self
}
}
}
//Call this function when the tap is recognized.
func DismissKeyboard(){
contentView.endEditing(true)
}
// Stop Editing on Return Key Tap.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//edited for next button
weak var activeField: UITextField?
func keyboardDidShow(_ notification: Notification) {
//when a textfield is edited lift the button above the keyboard
if let activeField = self.activeField,let keyboardSize =
(notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as?
NSValue)?.cgRectValue {
//20 in insets and offset is just padding
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom:
keyboardSize.height + 20 + nextButton.bounds.height, right: 0.0)
self.scrollView.contentInset = contentInsets
var aRect = self.view.frame
aRect.size.height -= keyboardSize.height
let bottomPoint = CGPoint(x: activeField.frame.origin.x, y:activeField.frame.origin.y)
if aRect.contains(bottomPoint){
let scrollPoint = CGPoint(x: 0.0, y: bottomPoint.y - keyboardSize.height - 20 - nextButton.bounds.height)
scrollView.setContentOffset(scrollPoint, animated: true)
}
}
}
func keyboardWillHide(_ notification: Notification) {
let contentInsets = UIEdgeInsets.zero
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
}
//Keep track of which textfield is being edited to make sure the field is visible when keyboard pops up
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
self.activeField = nil
}
//register for keyboard notifications
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector:
#selector(keyboardDidShow),
name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector:
#selector(keyboardWillHide), name:
NSNotification.Name.UIKeyboardWillHide, object: nil)
}
//remove keyBoard observers
func deregisterFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name:
NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name:
NSNotification.Name.UIKeyboardWillHide, object: nil)
}
deinit {
//deregister keyboard notifications
deregisterFromKeyboardNotifications()
}
} //end of class
现在再走一步。我们得处理按钮上移的问题。不只是杀死这个控制器并在其中放置更多的处理,您可以子类底部约束来处理它。(只需确保不向底部添加顶约束。)下面是一个在项目中删除的约束。
import UIKit
class AvoidingConstraint: NSLayoutConstraint {
private var offset : CGFloat = 0
private var keyboardVisibleHeight : CGFloat = 0
override public func awakeFromNib() {
super.awakeFromNib()
offset = constant
NotificationCenter.default.addObserver(self, selector: #selector(AvoidingConstraint.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AvoidingConstraint.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: Notification
func keyboardWillShowNotification(_ notification: Notification) {
if let userInfo = notification.userInfo {
if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
let frame = frameValue.cgRectValue
keyboardVisibleHeight = frame.size.height
}
self.updateConstant()
switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
case let (.some(duration), .some(curve)):
let options = UIViewAnimationOptions(rawValue: curve.uintValue)
UIView.animate(
withDuration: TimeInterval(duration.doubleValue),
delay: 0,
options: options,
animations: {
UIApplication.shared.keyWindow?.layoutIfNeeded()
return
}, completion: { finished in
})
default:
break
}
}
}
func keyboardWillHideNotification(_ notification: NSNotification) {
keyboardVisibleHeight = 0
self.updateConstant()
if let userInfo = notification.userInfo {
switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
case let (.some(duration), .some(curve)):
let options = UIViewAnimationOptions(rawValue: curve.uintValue)
UIView.animate(
withDuration: TimeInterval(duration.doubleValue),
delay: 0,
options: options,
animations: {
UIApplication.shared.keyWindow?.layoutIfNeeded()
return
}, completion: { finished in
})
default:
break
}
}
}
func updateConstant() {
self.constant = offset + keyboardVisibleHeight
}
}
将其添加到项目中的文件中。然后,您所要做的就是为您在故事板中的按钮设置底部约束,将其更改为这个子类。只需确保没有顶约束。持有滚动视图的视图需要对主视图具有底部约束,而不需要为按钮留出足够的空间。运行这个项目并享受。如果这个解释还不够,请参阅测试项目链接。https://www.dropbox.com/s/ir5x324mvhhne64/ScrollView.zip?dl=0
发布于 2017-03-03 09:51:13
我认为只有当字段被键盘覆盖时,你才应该向上移动,就像我几天前做的那样:
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue ?? NSValue()).cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
UIView.animate(withDuration: 0.2) {
if notification.name == Notification.Name.UIKeyboardWillHide {
self.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height)
} else {
let offset = (self.view.frame.size.height - self.activeField.frame.maxY) - keyboardViewEndFrame.height
if offset < 0 {
self.view.frame = CGRect(x: 0, y: offset, width: self.view.width, height: self.view.height)
} else {
self.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height)
}
}
}
基本上,您只需要为键盘处理计时添加逻辑,如果键盘帧超过textfield帧,则应该处理它。希望能帮上忙。
https://stackoverflow.com/questions/42543593
复制相似问题