ios - poner - recuperar notificaciones iphone
Cómo desplazarse hasta la parte inferior de una UITableView en el iPhone antes de que aparezca la vista (30)
Detalles
xCode 8.3.2, swift 3.1
Código
import UIKit
extension UITableView {
func scrollToBottom(animated: Bool) {
let y = contentSize.height - frame.size.height
setContentOffset(CGPoint(x: 0, y: (y<0) ? 0 : y), animated: animated)
}
}
Uso
tableView.scrollToBottom(animated: true)
Tengo una UITableView
que está poblada con celdas de altura variable. Me gustaría que la tabla se desplace hacia abajo cuando la vista se muestre a la vista.
Actualmente tengo la siguiente función
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[log count]-1 inSection:0];
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
log es una matriz mutable que contiene los objetos que componen el contenido de cada celda.
El código anterior funciona bien en viewDidAppear
pero tiene el desafortunado efecto secundario de mostrar la parte superior de la tabla cuando aparece la vista por primera vez y luego saltar al fondo. Preferiría que la table view
se desplazara hacia abajo antes de que aparezca.
Intenté el desplazamiento en viewWillAppear
y viewDidLoad
pero en ambos casos los datos no se han cargado aún en la tabla y ambos lanzan una excepción.
Cualquier orientación sería muy apreciada, incluso si solo es cuestión de decirme lo que tengo es todo lo que es posible.
Aquí hay una extensión que implementé en Swift 2.0. Estas funciones deben tableview
se haya cargado la tableview
:
import UIKit
extension UITableView {
func setOffsetToBottom(animated: Bool) {
self.setContentOffset(CGPointMake(0, self.contentSize.height - self.frame.size.height), animated: true)
}
func scrollToLastRow(animated: Bool) {
if self.numberOfRowsInSection(0) > 0 {
self.scrollToRowAtIndexPath(NSIndexPath(forRow: self.numberOfRowsInSection(0) - 1, inSection: 0), atScrollPosition: .Bottom, animated: animated)
}
}
}
Creo que la manera más fácil es esta:
if (self.messages.count > 0)
{
[self.tableView
scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messages.count-1
inSection:0]
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
Versión de Swift 3:
if messages.count > 0 {
userDefinedOptionsTableView.scrollToRow(at: IndexPath(item:messages.count-1, section: 0), at: .bottom, animated: true)
}
Creo que las soluciones antiguas no funcionan con swift3.
Si conoce las filas numéricas de la tabla, puede usar:
tableView.scrollToRow(
at: IndexPath(item: listCountInSection-1, section: sectionCount - 1 ),
at: .top,
animated: true)
Creo que llamando [table setContentOffset:CGPointMake(0, CGFLOAT_MAX)]
hará lo que quiera.
De la respuesta de Jacob , este es el código:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.messagesTableView.contentSize.height > self.messagesTableView.frame.size.height)
{
CGPoint offset = CGPointMake(0, self.messagesTableView.contentSize.height - self.messagesTableView.frame.size.height);
[self.messagesTableView setContentOffset:offset animated:YES];
}
}
Debería usar UITableViewScrollPositionBottom
en UITableViewScrollPositionBottom
lugar.
Después de mucho toquetear esto es lo que funcionó para mí:
var viewHasAppeared = false
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if !viewHasAppeared { goToBottom() }
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
viewHasAppeared = true
}
private func goToBottom() {
guard data.count > 0 else { return }
let indexPath = NSIndexPath(forRow: data.count - 1, inSection: 0)
tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
tableView.layoutIfNeeded()
}
La clave resultó no estar ajustando scrollToRowAtIndexPath
dentro de dispatch_async
como algunos han sugerido, sino simplemente siguiéndolo con una llamada a layoutIfNeeded
.
Mi comprensión de esto es que, al llamar al método de desplazamiento en el hilo actual, se garantiza que el desplazamiento de desplazamiento se establece inmediatamente, antes de que se muestre la vista. Cuando estaba enviando al hilo principal, la vista se mostraba por un instante antes de que el rollo tuviera efecto.
(También NB necesita el indicador viewHasAppeared
porque no desea goToBottom
a goToBottom
cada vez que se viewDidLayoutSubviews
. Se llama, por ejemplo, cada vez que cambia la orientación).
En Swift 3.0
self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
En Swift, solo necesitas
self.tableView.scrollToNearestSelectedRowAtScrollPosition(UITableViewScrollPosition.Bottom, animated: true)
para que se desplace automáticamente al botón
En iOS, esto funcionó bien para mí
CGFloat height = self.inputTableView.contentSize.height;
if (height > CGRectGetHeight(self.inputTableView.frame)) {
height -= (CGRectGetHeight(self.inputTableView.frame) - CGRectGetHeight(self.navigationController.navigationBar.frame));
}
else {
height = 0;
}
[self.inputTableView setContentOffset:CGPointMake(0, height) animated:animated];
Necesita ser llamado desde viewDidLayoutSubviews
En realidad, una manera "rápida" de hacerlo rápido es:
var lastIndex = NSIndexPath(forRow: self.messages.count - 1, inSection: 0)
self.messageTableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
trabajo perfecto para mi
En swift 3.0 Si desea ir a cualquier celda particular de la tabla vista Cambiar el índice de la celda Valor como cambiar el valor "self.yourArr.count".
self.yourTable.reloadData()
self.scrollToBottom()
func scrollToBottom(){
DispatchQueue.global(qos: .background).async {
let indexPath = IndexPath(row: self.yourArr.count-1, section: 0)
self.tblComment.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
Es por supuesto un error. Probablemente en algún lugar de su código utilice table.estimatedRowHeight = value
(por ejemplo, 100). Reemplace este valor por el valor más alto que crea que podría obtenerse una altura de fila , por ejemplo 500. Esto debería resolver el problema en combinación con el siguiente código:
//auto scroll down example
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
self.table.scrollToRowAtIndexPath(NSIndexPath(forRow: self.Messages.count - 1, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
})
Estoy usando el diseño automático y ninguna de las respuestas funcionó para mí. Aquí está mi solución que finalmente funcionó:
@property (nonatomic, assign) BOOL shouldScrollToLastRow;
- (void)viewDidLoad {
[super viewDidLoad];
_shouldScrollToLastRow = YES;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// Scroll table view to the last row
if (_shouldScrollToLastRow)
{
_shouldScrollToLastRow = NO;
[self.tableView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
}
}
Función en swift 3 scroll to bottom
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(false)
//scroll down
if lists.count > 2 {
let numberOfSections = self.tableView.numberOfSections
let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)
let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
}
}
Gracias Jacob por la respuesta. realmente útil si alguien interesante con la versión de monotouch c #
private void SetScrollPositionDown()
{
if (tblShoppingListItem.ContentSize.Height > tblShoppingListItem.Frame.Size.Height)
{
PointF offset = new PointF(0,
tblShoppingListItem.ContentSize.Height -
tblShoppingListItem.Frame.Size.Height);
tblShoppingListItem.SetContentOffset(offset,true );
}
}
La respuesta aceptada no funcionó con mi tabla (miles de filas, carga dinámica) pero el código siguiente funciona:
- (void)scrollToBottom:(id)sender {
if ([self.sections count] > 0) {
NSInteger idx = [self.sections count] - 1;
CGRect sectionRect = [self.tableView rectForSection:idx];
sectionRect.size.height = self.tableView.frame.size.height;
[self.tableView scrollRectToVisible:sectionRect animated:NO];
}
}
La solución aceptada por @JacobRelkin no funcionó en iOS 7.0 utilizando Auto Layout.
Tengo una subclase personalizada de UIViewController
y agregué una variable de instancia _tableView
como subvista de su view
. Posicione _tableView
usando el diseño automático. Intenté llamar a este método al final de viewDidLoad
e incluso en viewWillAppear:
Ninguno funcionó.
Entonces, agregué el siguiente método a mi subclase personalizada de UIViewController
.
- (void)tableViewScrollToBottomAnimated:(BOOL)animated {
NSInteger numberOfRows = [_tableView numberOfRowsInSection:0];
if (numberOfRows) {
[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:numberOfRows-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
}
}
Llamar a [self tableViewScrollToBottomAnimated:NO]
al final de viewDidLoad
funciona. Desafortunadamente, también causa que tableView:heightForRowAtIndexPath:
tres veces para cada celda.
No es necesario desplazarse, puede hacerlo utilizando este código:
[YOURTABLEVIEWNAME setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
Para Swift 3 (Xcode 8.1):
override func viewDidAppear(_ animated: Bool) {
let numberOfSections = self.tableView.numberOfSections
let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)
let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
}
Para Swift:
if tableView.contentSize.height > tableView.frame.size.height
{
let offset = CGPoint(x: 0, y: tableView.contentSize.height - tableView.frame.size.height)
tableView.setContentOffset(offset, animated: false)
}
Quería que la mesa se cargara con el extremo de la tabla que se muestra en el marco. He encontrado usando
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0];
[[self tableView] scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
no funcionó porque dio un error cuando la altura de la tabla era menor que la altura del cuadro. Tenga en cuenta que mi mesa solo tiene una sección.
La solución que funcionó para mí fue implementar el siguiente código en viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// on the initial cell load scroll to the last row (ie the latest Note)
if (initialLoad==TRUE) {
initialLoad=FALSE;
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0];
[[self tableView] scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
CGPoint offset = CGPointMake(0, (1000000.0));
[self.tableView setContentOffset:offset animated:NO];
}
}
BOOL ivar initialLoad se establece en TRUE en viewDidLoad.
Si está configurando el marco para la tabla vista programáticamente, asegúrese de que está configurando el marco correctamente.
Si necesita desplazarse al final EXACTO del contenido, puede hacerlo así:
- (void)scrollToBottom
{
CGFloat yOffset = 0;
if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {
yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
}
[self.tableView setContentOffset:CGPointMake(0, yOffset) animated:NO];
}
Si tiene que cargar los datos de forma asincrónica antes de desplazarse hacia abajo, aquí está la posible solución:
tableView.alpha = 0 // We want animation!
lastMessageShown = false // This is ivar
viewModel.fetch { [unowned self] result in
self.tableView.reloadData()
if !self.lastMessageShown {
dispatch_async(dispatch_get_main_queue()) { [unowned self] in
if self.rowCount > 0 {
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: self.rowCount, inSection: 0), atScrollPosition: .Bottom, animated: false)
}
UIView.animateWithDuration(0.1) {
self.tableView.alpha = 1
self.lastMessageShown = true // Do it once
}
}
}
}
Usando las soluciones anteriores, esto se desplazará al final de la tabla (solo si el contenido de la tabla se carga primero):
//Scroll to bottom of table
CGSize tableSize = myTableView.contentSize;
[myTableView setContentOffset:CGPointMake(0, tableSize.height)];
[self.tableViewInfo scrollRectToVisible: CGRectMake (0, self.tableViewInfo.contentSize.height-self.tableViewInfo.height, self.tableViewInfo.width, self.tableViewInfo.height) animado: SÍ];
Usa este código simple para desplazarte a TableView bottom
NSInteger rows = [tableName numberOfRowsInSection:0];
if(rows > 0) {
[tableName scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:rows-1 inSection:0]
atScrollPosition:UITableViewScrollPositionBottom
animated:YES];
}
func scrollToBottom() {
let sections = self.chatTableView.numberOfSections
if sections > 0 {
let rows = self.chatTableView.numberOfRows(inSection: sections - 1)
let last = IndexPath(row: rows - 1, section: sections - 1)
DispatchQueue.main.async {
self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
}
}
}
deberías agregar
DispatchQueue.main.async {
self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
}
o no se desplazará hacia abajo.