我可以覆盖滚动视图的自动行为以滚动到第一响应者吗?
我在 UIScrollView 中有一个 UITextField (几层深)。我正在观看 UIKeyboardDidShowNotification,并且当我手动更改第一响应者时也会调用相同的代码(我可能会更改为不同的文本字段而不会暂时隐藏键盘)。在该代码中,我使用 scrollRectToVisible:animated:
来确保 UITextField 可见。
我非常头疼地调试为什么这看起来很有趣,但我现在意识到 UIScrollView 会自动确保第一响应者在其范围内。我正在更改 UIScrollView 的框架,以便它不会隐藏在键盘后面。
但是,我的代码可能比他们的代码稍微聪明一些,因为我不仅想显示 UITextField,还想显示一些附近的相关视图。我会尝试展示这些观点(如果它们适合的话);如果不是这样,我会尝试尽可能多地显示它们,但至少确保 UITextField 可见。所以我想保留我的自定义代码。
自动行为会干扰我的代码。我看到的是滚动视图轻轻地向上滚动,以便内容的底部边缘可见,然后它向下捕捉到我的代码告诉它的位置。
是否有办法阻止 UIScrollView 执行其将第一个响应者滚动到视图中的默认功能?
更多信息
在查看文档时,我读到他们建议更改滚动视图的 contentInset 而不是框架。我改变了这一点并消除了一些不可预测的行为,但它并没有解决这个特定的问题。
我认为发布所有代码不一定那么有用。但这是当时的关键呼吁和重要属性的价值。我只会为 CGRect 编写 4 元组;我的意思是(x,y,宽度,高度)。
[scrollView scrollRectToVisible:(116.2, 71.2, 60, 243) animated:YES];
scrollView.bounds == (0, 12, 320, 361)
scrollView.contentInset == UIEdgeInsetsMake(0, 0, 118, 0)
textField.frame == (112.2, 222.6, 24, 24)
转换为直接子视图的坐标的scrollView == (134.2, 244.6, 24, 24)
转换为滚动视图的坐标 == (134.2, 244.6, 24, 24)
因此,由于插入,滚动视图底部边缘实际上位于 y == 243 处。
请求的矩形扩展到 y == 314.2。
文本字段扩展到 y == 268.6。
两者皆出界。 scrollRectToVisible 正在尝试解决这些问题之一。标准 UIScrollView / UITextField 行为正在尝试修复另一个。他们没有提出完全相同的解决方案。
I have a UITextField inside a UIScrollView (a few levels deep). I am watching UIKeyboardDidShowNotification, and also calling the same code when I manually change the first responder (I might change to a different text field without momentarily hiding the keyboard). In that code I use scrollRectToVisible:animated:
to make sure the UITextField is visible.
I was having a huge headache debugging why that was acting funny, but I realized now that UIScrollView automatically ensures that the first responder is within its bounds. I am changing the frame of the UIScrollView so that none of it is hidden behind the keyboard.
However, my code can be slightly smarter than their code, because I want to show not only the UITextField, but some nearby related views as well. I try to show those views if they will fit; if not whatever, I try to show as much of them as I can but at least ensure that the UITextField is visible. So I want to keep my custom code.
The automatic behavior interferes with my code. What I see is the scroll view gently scroll up so that the bottom edge of my content is visible, then it snaps down to where my code told it to position.
Is there anyway to stop the UIScrollView from doing its default capability of scrolling the first responder into view?
More Info
On reviewing the documentation I read that they advise to change the scroll view's contentInset instead of frame. I changed that and eliminated some unpredictable behavior, but it didn't fix this particular problem.
I don't think posting all the code would necessarily be that useful. But here is the critical call and the values of important properties at that time. I will just write 4-tuples for CGRects; I mean (x, y, width, height).
[scrollView scrollRectToVisible:(116.2, 71.2, 60, 243) animated:YES];
scrollView.bounds == (0, 12, 320, 361)
scrollView.contentInset == UIEdgeInsetsMake(0, 0, 118, 0)
textField.frame == (112.2, 222.6, 24, 24)
converted to coordinates of the immediate subview of scrollView == (134.2, 244.6, 24, 24)
converted to coordinates of scrollView == (134.2, 244.6, 24, 24)
So the scroll view bottom edge is really at y == 243 because of the inset.
The requested rectangle extends to y == 314.2.
The text field extends to y == 268.6.
Both are out of bounds. scrollRectToVisible is trying to fix one of those problems. The standard UIScrollView / UITextField behavior is trying to fix the other. They don't come up with quite the same solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我没有测试这种特殊情况,但我通过子类化滚动视图并覆盖 setContentOffset: 和 setContentOffset:animated: 设法防止滚动视图在顶部和底部弹跳。滚动视图在每次滚动移动时都会调用它,所以我相当确定它们在滚动到文本字段时会被调用。
您可以使用委托方法 textFieldDidBeginEditing: 来确定何时允许滚动。
在代码中:
如果您当前的滚动行为适用于 setContentOffset: 覆盖,只需将其放置在 else 块内(或者最好放在从 else 块调用的方法中)。
I didn't test this particular situation, but I've managed to prevent a scrollview from bouncing at the top and bottom by subclassing the scrollview and overriding setContentOffset: and setContentOffset:animated:. The scrollview calls this at every scroll movement, so I'm fairly certain they will be called when scrolling to the textfield.
You can use the delegate method textFieldDidBeginEditing: to determine when the scroll is allowed.
In code:
If your current scroll behaviour works with a setContentOffset: override, just place it inside the else blocks (or preferably, in a method you call from the else blocks).
在我的项目中,我通过仅在延迟一段时间后才执行滚动成功地实现了这一点。
此外,还有其他可能性使您的视图具有附加视图,成为第一响应者并愚弄滚动视图在哪里滚动。还没有测试过这个。
In my project I have succeeded to achieve this by performing my scroll only after some delay.
Also there is other possibility to make your view with additional views to be first responder and fool scroll view where to scroll. Haven't tested this yet.
这可能没用,但是您是否尝试过在调用
scrollrectToVisible:
之前将scrollView.userInteractionEnabled
设置为 NO?然后将其设置回 YES?它可能会阻止自动滚动行为。This may turn out to be useless, but have you tried setting
scrollView.userInteractionEnabled
to NO before callingscrollrectToVisible:
& then setting it back to YES? It may prevent the automatic scrolling behavior.尝试将视图自动调整大小更改为 UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin。默认值为
FlexibleTopMargin
,所以也许这就是原因。顺便说一句scrollRectToVisible:
正在使用scrollView.contentSize
。另外,您可以尝试先更改
scrollView
大小,然后应用scrollRectToVisible:
更改。首先改变框架,然后改变内容。 (也许观察键盘确实出现了事件)Try changing the view autoresizing to
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin
. The default isFlexibleTopMargin
so maybe thats the reason. btwscrollRectToVisible:
is using thescrollView.contentSize
.The other thing you can try to change the
scrollView
size first and then apply thescrollRectToVisible:
change. First frame change, then content change. (Maybe observe the keyboard did appear event)从 iOS 14 开始,自动滚动行为似乎特别有问题。我通过子类化 UIScrollView 并覆盖
setContentOffset
不执行任何操作来缓解这个问题。这是我的代码的基础。这是可行的,但您必须重新实现通常免费获得的许多滚动视图行为和方法。由于
scrollRectToView
和scrollToView
都使用setContentOffset
如果您希望它们工作,您还必须重新实现它们。The automatic scrolling behavior seems to be especially buggy starting in iOS 14. I alleviated the problem by subclassing UIScrollView and overriding
setContentOffset
to do nothing. Here is the bases of my code.This works but you have to deal with reimplementing many of the scroll views behaviors and methods that you normally get for free. Since
scrollRectToView
andscrollToView
both usesetContentOffset
you also have to reimplement these if you want them to work.