Respostas:
Você pode usar a setContentOffset:animated:
função do UIScrollView para rolar para qualquer parte da exibição do conteúdo. Aqui está um código que rolaria para a parte inferior, supondo que seu scrollView seja self.scrollView
:
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
Espero que ajude!
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
contentSize
for menor que bounds
. Por isso deve ser assim:scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
let bottomOffsetY = max(collectionView.contentSize.height - collectionView.bounds.height + collectionView.contentInset.bottom, 0)
Versão rápida da resposta aceita para facilitar a colagem de cópias:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)
Solução mais simples:
[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];
Apenas um aprimoramento para a resposta existente.
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
Ele também cuida da parte inferior inferior (caso você esteja usando isso para ajustar a visualização de rolagem quando o teclado estiver visível)
Uma implementação rápida:
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-o:
yourScrollview.scrollToBottom(animated: true)
Definir o deslocamento do conteúdo para a altura do tamanho do conteúdo está errado: ele rola a parte inferior do conteúdo para o topo da visualização de rolagem e, portanto, fora de vista.
A solução correta é rolar a parte inferior do conteúdo até a parte inferior da visualização de rolagem, desta forma ( sv
é o 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];
}
if (sv.contentOffset.y + csz.height > bsz.height) {
?
setContentOffset:
comando que é importante.
Uma solução Swift 2.2, levando contentInset
em consideração
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
Isso deve estar em uma extensão
extension UIScrollView {
func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
setContentOffset(bottomOffset, animated: true)
}
}
Observe que você pode verificar se bottomOffset.y > 0
antes de rolar
E se contentSize
for menor que bounds
?
Para Swift é:
scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
Role para cima
- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];
Role para baixo
- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
- [scrollView setContentOffset:bottomOffset animated:YES];
Eu também encontrei outra maneira útil de fazer isso no caso de você estar usando uma UITableview (que é uma subclasse de UIScrollView):
[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Parece que todas as respostas aqui não levaram em consideração a área segura. Desde o iOS 11, o iPhone X apresentou uma área segura. Isso pode afetar o scrollView contentInset
.
Para iOS 11 e superior, role a página corretamente para baixo com o conteúdo incluído. Você deve usar em adjustedContentInset
vez de contentInset
. Verifique este código:
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
):extension UIScrollView {
func scrollsToBottom(animated: Bool) {
let bottomOffset = CGPoint(x: contentOffset.x,
y: contentSize.height - bounds.height + adjustedContentInset.bottom)
setContentOffset(bottomOffset, animated: animated)
}
}
Referências:
Rápido:
Você pode usar uma extensão como esta:
extension UIScrollView {
func scrollsToBottom(animated: Bool) {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
setContentOffset(bottomOffset, animated: animated)
}
}
Usar:
scrollView.scrollsToBottom(animated: true)
Categoria para o resgate!
Adicione isso a um cabeçalho de utilitário compartilhado em algum lugar:
@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end
E então para a implementação desse utilitário:
@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
{
CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
[self setContentOffset:bottomOffset animated:animated];
}
@end
Em seguida, implemente-o onde quiser, por exemplo:
[[myWebView scrollView] scrollToBottomAnimated:YES];
Para ScrollView horizontal
Se você gosta de mim tem um ScrollView horizontal e deseja rolar até o final (no meu caso, à direita), é necessário alterar algumas partes da resposta aceita:
Objetivo-C
CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];
Rápido
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)
Se você alterar de alguma forma o scrollView contentSize (por exemplo, adicionar algo ao stackView que está dentro do scrollView), você deve chamarscrollView.layoutIfNeeded()
antes de rolar, caso contrário, não fará nada.
Exemplo:
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)
}
Uma boa maneira de garantir que a parte inferior do seu conteúdo fique visível é usar a fórmula:
contentOffsetY = MIN(0, contentHeight - boundsHeight)
Isso garante que a borda inferior do seu conteúdo esteja sempre igual ou acima da borda inferior da visualização. Isso MIN(0, ...)
é necessário porque UITableView
(e provavelmente UIScrollView
) garante contentOffsetY >= 0
quando o usuário tenta rolar visivelmente contentOffsetY = 0
. Isso parece muito estranho para o usuário.
O código para implementar isso é:
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];
}
Se você não precisa de animação, isso funciona:
[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];
Embora a Matt
solução me pareça correta, é necessário levar em conta também a exibição da coleção, se houver uma que foi configurada.
O código adaptado será:
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];
}
Solução para rolar para o último item de uma tabela
Swift 3:
if self.items.count > 0 {
self.tableView.scrollToRow(at: IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
}
Não funcionou para mim, quando eu tentei usá-lo em UITableViewController
on self.tableView
(iOS 4.1)
, após a adição footerView
. Rola para fora das bordas, mostrando a tela preta.
Solução alternativa:
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];
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];
Descobri que contentSize
isso realmente não reflete o tamanho real do texto; portanto, ao tentar rolar para o final, ficará um pouco fora. A melhor maneira de determinar o tamanho real conteúdo é realmente usar o NSLayoutManager
's usedRectForTextContainer:
método:
UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;
Para determinar quanto texto realmente é mostrado no UITextView
, você pode calculá-lo subtraindo as inserções do contêiner de texto da altura do quadro.
UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
Então fica fácil rolar:
// 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;
Alguns números para referência sobre o que os diferentes tamanhos representam para um vazio 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)
Estenda o UIScrollView para adicionar um método 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)
}
}
}
Versão Xamarin.iOSUICollectionView
da resposta aceita para facilitar a cópia e a colagem
var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);
CollectionView.SetContentOffset (bottomOffset, false);