使用iOS SDK:
我有一个带UITextFields的UIView,可以启动键盘。我需要它能够:
启动键盘后,允许滚动UIScrollView的内容以查看其他文本字段自动“跳转”(通过向上滚动)或缩短
我知道我需要一个UIScrollView。我已经尝试将UIView的类更改为UIScrollView,但仍然无法上下滚动文本框。
我需要UIView和UIScrollView吗?一个在另一个里面吗?
要自动滚动到活动文本字段,需要执行哪些操作?
理想情况下,尽可能多的组件设置将在Interface Builder中完成。我只想编写需要的代码。
注意:我使用的UIView(或UIScrollView)是由一个选项卡(UITabBar)启动的,它需要正常工作。
我正在添加滚动条,只为键盘出现时使用。尽管不需要它,但我觉得它提供了一个更好的界面,例如,用户可以滚动和更改文本框。
当键盘上下移动时,我可以改变UIScrollView的框架大小。我只是在使用:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50); // Resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
// Keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.origin.x,
scrollView.frame.origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); // Resize
}
然而,这不会自动“向上移动”或将可见区域中的下部文本字段居中,这是我真正想要的。
我们可以为Swift 4.1提供用户给定的代码
let keyBoardSize = 80.0
func keyboardWillShow() {
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.origin.y < 0 {
viewMovedUp = false
}
}
func keyboardWillHide() {
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.origin.y < 0 {
viewMovedUp = false
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if sender.isEqual(mailTf) {
//move the main view, so that the keyboard does not hide it.
if view.frame.origin.y >= 0 {
viewMovedUp = true
}
}
}
func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
// if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {
rect.origin.y -= keyBoardSize
rect.size.height += keyBoardSize
}
else {
// revert back to the normal state.
rect.origin.y += keyBoardSize
rect.size.height -= keyBoardSize
}
view.frame = rect
UIView.commitAnimations()
}
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}
func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
这是我为特定布局想出的破解方案。此解决方案与Matt Gallagher的解决方案相似,即将一个部分滚动到视图中。我还是iPhone开发的新手,不熟悉布局的工作原理。因此,这个黑客。
我的实现需要支持在字段中单击时滚动,以及用户在键盘上选择下一个时滚动。
我有一个UIView,身高775。控件基本上以3人一组的方式分布在一个大的空间中。我最终得到了以下IB布局。
UIView -> UIScrollView -> [UI Components]
黑客来了
我将UIScrollView的高度设置为比实际布局(1250)大500个单位。然后,我创建了一个数组,其中包含我需要滚动到的绝对位置,以及一个基于IB标记号获取它们的简单函数。
static NSInteger stepRange[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};
NSInteger getScrollPos(NSInteger i) {
if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
return 0 ;
return stepRange[i] ;
}
现在,您需要做的就是在textFieldDidBeginEditing和textFieldShouldReturn中使用以下两行代码(如果要创建下一个字段导航,则使用后者)
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
一个例子。
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger nextTag = textField.tag + 1;
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {
[nextResponder becomeFirstResponder];
CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
else{
[textField resignFirstResponder];
}
return YES ;
}
此方法不像其他方法那样“向后滚动”。这不是必需的。同样,这是一个相当“高大”的UIView,我没有时间学习内部布局引擎。
在textFieldDidBginEditing和textFieldDidEndEditing中调用函数[self-animateTextField:textField up:YES],如下所示:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -130; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: @"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
我希望这段代码对你有所帮助。
雨燕5
func animateTextField(textField: UITextField, up: Bool) {
let movementDistance: CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up {
movement = movementDistance
} else {
movement = -movementDistance
}
UIView.animate(withDuration: movementDuration, delay: 0, options: [.beginFromCurrentState]) {
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
animateTextField(textField: textField, up: true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
animateTextField(textField: textField, up: false)
}
我发现@DK_是我开始使用的解决方案。然而,假设scrollView覆盖了整个视图。我不是这样的。我只想要一个滚动视图,以防键盘覆盖了登录屏幕上的下文本字段。因此,我的内容视图与滚动视图大小相同,比主视图小。
它也没有考虑到景观,这是我开始遇到麻烦的地方。玩了几天后,这是我的键盘显示:方法。
- (void)keyboardWasShown:(NSNotification*)aNotification
{
// A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
CGFloat height = 0;
NSDictionary* info = [aNotification userInfo];
CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.
CGRect scrollRect = scrollView.frame;
CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);
if (!CGRectIsNull(intersect))
{
height = intersect.size.height;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
// Figure out what the view rectangle is for the scrollView
CGPoint contentOffset = scrollView.contentOffset;
CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y); // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
visibleRect.size.height -= height;
CGRect activeRect = activeField.frame;
if (!CGRectContainsRect(visibleRect, activeRect))
{
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
我在使用自动布局时也遇到了一些困难。如果我没有正确完成布局,我就没有得到预期的滚动效果。有一件事让生活变得更加简单,那就是将所有要滚动的项目放在一个视图中,并将其作为滚动视图中的唯一项目。我把这个单一视图称为“内容视图”。
我认为关键部分是内容视图有一个设定的宽度和高度。这使得滚动视图能够准确地知道需要处理多少内容。这与通常的布局有点不同。通常情况下,视图会尽量占据更多空间。对于滚动视图的内容,您试图使视图尽可能地限制自己。内容视图允许您停止此操作。所以我给了我248的高度,并使用320的标准屏幕宽度作为我的宽度。
最终对我有用的布局如下:
滚动视图到超级视图:基本上我给了顶部、左侧和右侧的约束。水平空间-视图-滚动视图(0)垂直空间-视图-滚动视图(0)水平空间-滚动视图-视图(0)滚动视图高度:我将滚动视图设置为恒定高度。我不知道这是否真的有必要,但它有滚动视图本身的界限。高度-(248)-滚动视图滚动视图的内容视图:我给了所有方面的常量,顶部、左侧、底部和右侧。垂直空间-视图-滚动视图(0)垂直空间-滚动视图-视图(0)水平空间-视图-滚动视图(0)水平空间-滚动视图-视图(0)内容视图的维度。高度-(248)-视图宽度-(320)-视图