[英]UIScrollView scroll to bottom programmatically
How can I make a UIScrollView
scroll to the bottom within my code?如何让
UIScrollView
在我的代码中滚动到底部? Or in a more generic way, to any point of a subview?或者以更通用的方式,到子视图的任何一点?
You can use the UIScrollView's setContentOffset:animated:
function to scroll to any part of the content view.您可以使用 UIScrollView 的
setContentOffset:animated:
函数滚动到内容视图的任何部分。 Here's some code that would scroll to the bottom, assuming your scrollView is self.scrollView
:下面是一些会滚动到底部的代码,假设您的 scrollView 是
self.scrollView
:
Objective-C:目标-C:
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
Swift:迅速:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
Hope that helps!希望有帮助!
Swift version of the accepted answer for easy copy pasting:已接受答案的 Swift 版本,便于复制粘贴:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)
最简单的解决方案:
[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];
A swifty implementation:一个快速的实施:
extension UIScrollView {
func scrollToBottom(animated: Bool) {
if self.contentSize.height < self.bounds.size.height { return }
let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.size.height)
self.setContentOffset(bottomOffset, animated: animated)
}
}
use it:用它:
yourScrollview.scrollToBottom(animated: true)
Just an enhancement to the existing answer.只是对现有答案的增强。
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
It takes care of the bottom inset as well (in case you're using that to adjust your scroll view when the keyboard is visible)它也会处理底部的插图(以防您在键盘可见时使用它来调整滚动视图)
Setting the content offset to the height of the content size is wrong: it scrolls the bottom of the content to the top of the scroll view, and thus out of sight.将内容偏移设置为内容大小的高度是错误的:它将内容的底部滚动到滚动视图的顶部,从而看不见。
The correct solution is to scroll the bottom of the content to the bottom of the scroll view, like this ( sv
is the UIScrollView):正确的解决方案是将内容的底部滚动到滚动视图的底部,如下所示(
sv
是 UIScrollView):
CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
if (sv.contentOffset.y + bsz.height > csz.height) {
[sv setContentOffset:CGPointMake(sv.contentOffset.x,
csz.height - bsz.height)
animated:YES];
}
A Swift 2.2 solution, taking contentInset
into account Swift 2.2 解决方案,将
contentInset
考虑在内
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
This should be in an extension这应该在扩展中
extension UIScrollView {
func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
setContentOffset(bottomOffset, animated: true)
}
}
Note that you may want to check if bottomOffset.y > 0
before scroll请注意,您可能需要在滚动前检查
bottomOffset.y > 0
What if contentSize
is lower than bounds
?如果
contentSize
低于bounds
怎么办?
For Swift it is:对于 Swift,它是:
scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
Scroll To Top滚动到顶部
- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];
Scroll To Bottom滚动到底部
- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
- [scrollView setContentOffset:bottomOffset animated:YES];
Using UIScrollView's setContentOffset:animated:
function to scroll to the bottom in Swift.使用 UIScrollView 的
setContentOffset:animated:
函数在 Swift 中滚动到底部。
let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
It looks like all of the answers here didn't take the safe area into consideration.看起来这里的所有答案都没有考虑安全区域。 Since iOS 11, iPhone X had a safe area introduced.
从 iOS 11 开始,iPhone X 引入了安全区域。 This may affect the scrollView's
contentInset
.这可能会影响 scrollView 的
contentInset
。
For iOS 11 and above, to properly scroll to the bottom with the content inset included.对于 iOS 11 及更高版本,正确滚动到包含内容插入的底部。 You should use
adjustedContentInset
instead of contentInset
.您应该使用
adjustedContentInset
而不是contentInset
。 Check this code:检查此代码:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
contentOffset.x
): contentOffset.x
):extension UIScrollView {
func scrollsToBottom(animated: Bool) {
let bottomOffset = CGPoint(x: contentOffset.x,
y: contentSize.height - bounds.height + adjustedContentInset.bottom)
setContentOffset(bottomOffset, animated: animated)
}
}
References:参考:
在您使用 UITableview(它是 UIScrollView 的子类)的情况下,我还发现了另一种有用的方法:
[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Swift:迅速:
You could use an extension like this:你可以使用这样的扩展:
extension UIScrollView {
func scrollsToBottom(animated: Bool) {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
setContentOffset(bottomOffset, animated: animated)
}
}
Use:用:
scrollView.scrollsToBottom(animated: true)
With an (optional) footerView
and contentInset
, the solution is:使用(可选)
footerView
和contentInset
,解决方案是:
CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom);
if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];
If you somehow change scrollView contentSize (ex. add something to stackView which is inside scrollView) you must call scrollView.layoutIfNeeded()
before scrolling, otherwise it does nothing.如果您以某种方式更改了 scrollView contentSize (例如,向位于 scrollView 内的 stackView 添加一些内容),您必须在滚动前调用
scrollView.layoutIfNeeded()
,否则它什么都不做。
Example:例子:
scrollView.layoutIfNeeded()
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
if(bottomOffset.y > 0) {
scrollView.setContentOffset(bottomOffset, animated: true)
}
valdyr, hope this will help you: valdyr,希望这会帮助你:
CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height);
if (bottomOffset.y > 0)
[textView setContentOffset: bottomOffset animated: YES];
For Horizontal ScrollView对于水平滚动视图
If you like me has a Horizontal ScrollView and want to scroll to end of it (in my case to most right of it), you need to change some parts of the accepted answer:如果你喜欢我有一个 Horizontal ScrollView 并且想要滚动到它的末尾(在我的情况下是它的最右边),你需要更改已接受答案的某些部分:
Objective-C目标-C
CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];
Swift迅速
let rightOffset: CGPoint = CGPoint(x: self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, y: 0)
self.scrollView.setContentOffset(rightOffset, animated: true)
Category to the rescue!类别来救援!
Add this to a shared utility header somewhere:将此添加到某处的共享实用程序标头中:
@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end
And then to that utility implementation:然后到该实用程序实现:
@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
{
CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
[self setContentOffset:bottomOffset animated:animated];
}
@end
Then Implement it wherever you like, for instance:然后在任何你喜欢的地方实现它,例如:
[[myWebView scrollView] scrollToBottomAnimated:YES];
A good way to ensure the bottom of your content is visible is to use the formula:确保内容底部可见的一个好方法是使用以下公式:
contentOffsetY = MIN(0, contentHeight - boundsHeight)
This ensures the bottom edge of your content is always at or above the bottom edge of the view.这可确保内容的底部边缘始终位于视图底部边缘或上方。 The
MIN(0, ...)
is required because UITableView
(and probably UIScrollView
) ensures contentOffsetY >= 0
when the user tries to scroll by visibly snapping contentOffsetY = 0
. MIN(0, ...)
是必需的,因为UITableView
(可能还有UIScrollView
)在用户尝试通过明显捕捉contentOffsetY = 0
来滚动时确保contentOffsetY >= 0
contentOffsetY = 0
。 This looks pretty weird to the user.这对用户来说看起来很奇怪。
The code to implement this is:实现这一点的代码是:
UIScrollView scrollView = ...;
CGSize contentSize = scrollView.contentSize;
CGSize boundsSize = scrollView.bounds.size;
if (contentSize.height > boundsSize.height)
{
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.y = contentSize.height - boundsSize.height;
[scrollView setContentOffset:contentOffset animated:YES];
}
如果你不需要动画,这有效:
[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];
While Matt
solution seems correct to me you need to take in account also the collection view inset if there is one that has been set-up.虽然
Matt
解决方案对我来说似乎是正确的,但如果已经设置了集合视图,您还需要考虑集合视图插图。
The adapted code will be:改编后的代码将是:
CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
NSInteger bottomInset = sv.contentInset.bottom;
if (sv.contentOffset.y + bsz.height + bottomInset > csz.height) {
[sv setContentOffset:CGPointMake(sv.contentOffset.x,
csz.height - bsz.height + bottomInset)
animated:YES];
}
In swift:迅速:
if self.mainScroll.contentSize.height > self.mainScroll.bounds.size.height {
let bottomOffset = CGPointMake(0, self.mainScroll.contentSize.height - self.mainScroll.bounds.size.height);
self.mainScroll.setContentOffset(bottomOffset, animated: true)
}
Solution to scroll to last item of a table View :滚动到表视图的最后一项的解决方案:
Swift 3 :斯威夫特3:
if self.items.count > 0 {
self.tableView.scrollToRow(at: IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
}
CGFloat yOffset = scrollView.contentOffset.y;
CGFloat height = scrollView.frame.size.height;
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat distance = (contentHeight - height) - yOffset;
if(distance < 0)
{
return ;
}
CGPoint offset = scrollView.contentOffset;
offset.y += distance;
[scrollView setContentOffset:offset animated:YES];
I found that contentSize
doesn't really reflect the actual size of the text, so when trying to scroll to the bottom, it will be a little bit off.我发现
contentSize
并没有真正反映文本的实际大小,所以当试图滚动到底部时,它会有点偏离。 The best way to determine the actual content size is actually to use the NSLayoutManager
's usedRectForTextContainer:
method:确定实际内容大小的最佳方法实际上是使用
NSLayoutManager
的usedRectForTextContainer:
方法:
UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;
To determine how much text actually is shown in the UITextView
, you can calculate it by subtracting the text container insets from the frame height.要确定
UITextView
实际显示的文本数量,您可以通过从框架高度中减去文本容器插入来计算它。
UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
Then it becomes easy to scroll:然后它变得容易滚动:
// if you want scroll animation, use contentOffset
UITextView *textView;
textView.contentOffset = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
// if you don't want scroll animation
CGRect scrollBounds = textView.bounds;
scrollBounds.origin = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
textView.bounds = scrollBounds;
Some numbers for reference on what the different sizes represent for an empty UITextView
.一些数字用于参考不同大小代表空
UITextView
。
textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)
Didn't work for me, when I tried to use it in UITableViewController
on self.tableView
(iOS 4.1)
, after adding footerView
.添加
footerView
后,当我尝试在self.tableView
(iOS 4.1)
上的UITableViewController
使用它时,对我footerView
。 It scrolls out of the borders, showing black screen.它滚动出边框,显示黑屏。
Alternative solution:替代解决方案:
CGFloat height = self.tableView.contentSize.height;
[self.tableView setTableFooterView: myFooterView];
[self.tableView reloadData];
CGFloat delta = self.tableView.contentSize.height - height;
CGPoint offset = [self.tableView contentOffset];
offset.y += delta;
[self.tableView setContentOffset: offset animated: YES];
Extend UIScrollView to add a scrollToBottom method:扩展 UIScrollView 以添加 scrollToBottom 方法:
extension UIScrollView {
func scrollToBottom(animated:Bool) {
let offset = self.contentSize.height - self.visibleSize.height
if offset > self.contentOffset.y {
self.setContentOffset(CGPoint(x: 0, y: offset), animated: animated)
}
}
}
To scroll to the bottom end, we have to work with the target view maximum height.要滚动到底部,我们必须使用目标视图的最大高度。
import UIKit
extension UIScrollView {
func scrollToBottomOf(targetView: UIView, animated: Bool) {
setContentOffset(CGPoint(x:targetView.frame.minX, y:targetView.frame.maxY), animated: animated)
}
}
//func invocation example
optionScrollView.scrollToBottomOf(targetView: self.optionsStackView, animated: false)
As explained here https://janeshswift.com/ios/swift/how-to-scroll-to-a-position-programmatically-in-uiscrollview/如此处所述https://janeshswift.com/ios/swift/how-to-scroll-to-a-position-programmatically-in-uiscrollview/
We can create a custom UIScrollView
extension as我们可以创建一个自定义的
UIScrollView
扩展作为
extension UIScrollView {
func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.height + self.contentInset.bottom)
self.setContentOffset(bottomOffset, animated: true)
}
func scrollToTop() {
let topOffset = CGPoint.zero
self.setContentOffset(topOffset, animated: true)
}
func scrollToRightEnd(animated: Bool) {
if self.contentSize.width < self.bounds.size.width { return }
let rightOffset = CGPoint(x: self.contentSize.width - self.bounds.size.width, y: 0)
self.setContentOffset(rightOffset, animated: animated)
}
func scrollToLeftEnd(animated: Bool) {
if self.contentSize.width < self.bounds.size.width { return }
let leftOffset = CGPoint.zero
self.setContentOffset(leftOffset, animated: animated)
}
}
Use It as --用作——
DispatchQueue.main.async {
self.itemsScrollView.scrollToBottom()
}
Xamarin.iOS version for UICollectionView
of the accepted answer for ease in copying and pasting已接受答案的
UICollectionView
的Xamarin.iOS版本,以便于复制和粘贴
var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);
CollectionView.SetContentOffset (bottomOffset, false);
Xamarin.iOS version of accepted answer接受答案的Xamarin.iOS版本
var bottomOffset = new CGPoint (0,
scrollView.ContentSize.Height - scrollView.Frame.Size.Height
+ scrollView.ContentInset.Bottom);
scrollView.SetContentOffset (bottomOffset, false);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.