J'ai un UITableView
non-scrolling dans un UIScrollView
. Je règle la taille de la variable UITableView
à la taille de son contenu.
Lorsque j'ajoute une ligne à la UITableView
, j'appelle insertRowsAtIndexPaths:withRowAnimation
: sur la UITableView
. Ensuite, j'appelle une méthode pour redimensionner le cadre de la UITableView
:
- (void)resizeTableViewFrameHeight
{
// Table view does not scroll, so its frame height should be equal to its contentSize height
CGRect frame = self.tableView.frame;
frame.size = self.tableView.contentSize;
self.tableView.frame = frame;
}
Il semble cependant que la contentSize
n’a pas été mise à jour à ce stade. Si je calcule manuellement le cadre dans la méthode ci-dessus en fonction du nombre de lignes et de sections, la méthode fonctionne correctement.
Ma question est, comment puis-je obtenir la UITableView
pour mettre à jour sa contentSize
? Je suppose que je pourrais appeler reloadData
et que ce serait probablement le cas, mais il semble inefficace de recharger tout le tableau lorsque je n'insère qu'une cellule.
Vous pouvez forcer UITableView à calculer la taille du contenu en appelant layoutIfNeeded
sur UITableView.
Exemple pour une sous-classe UITableViewController qui devrait figurer dans une vue de conteneur de taille variable:
- (CGSize)preferredContentSize
{
// Force the table view to calculate its height
[self.tableView layoutIfNeeded];
return self.tableView.contentSize;
}
Update 2016-07-28 Il s'agit d'un exemple Swift non testé de la même chose. Cela devrait fonctionner, mais si cela ne fonctionne pas, laissez un commentaire. Il pourrait y avoir des façons plus agréables ou plus idiomatiques de le faire. Malheureusement, je ne connais pas très bien Swift.
override var preferredContentSize: CGSize {
get {
self.tableView.layoutIfNeeded()
return self.tableView.contentSize
}
set {}
}
Bien que je n'aime pas le KVO (Key-Value Observing), c'est un bon moyen de savoir exactement quand la variable contentSize
de votre table a changé (plutôt que d'appeler simplement vos méthodes de mise à jour dans un tas d'endroits aléatoires). C'est assez simple à utiliser (bien que quelque peu cryptique et implicite). Pour observer les changements sur la contentSize
de votre table, procédez comme suit:
1) Devenez un observateur de la propriété contentSize
de votre table comme ceci:
[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL];
Cela se fait généralement dans le contrôleur de vue contenant la variable tableView
(comme dans viewDidLoad:
, par exemple).
2) Implémentez la méthode d’observation KVO et apportez les modifications nécessaires:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if(object == self.tableView && [keyPath isEqualToString:@"contentSize"]) {
// perform your updates here
}
}
3) Supprimez votre contrôleur de vue en tant qu’observateur à un moment donné (je l’appelle dans dealloc
). Vous faites ça comme ça:
- (void)dealloc {
[self.tableView removeObserver:self forKeyPath:@"contentSize"];
}
Essaye ça:
- (void)resizeTableViewFrameHeight
{
UITableView *tableView = self.tableView;
CGRect frame = tableView.frame;
frame.size.height = [tableView sizeThatFits:CGSizeMake(frame.size.width, HUGE_VALF)].height;
tableView.frame = frame;
}
Ajouter un observateur (dans mon échantillon dans viewDidLoad
tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
Observer la valeur
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let obj = object as? UITableView {
if obj == self.tableView && keyPath == "contentSize" {
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
//do stuff here
}
}
}
}
Retirer l'observateur lorsqu'il n'est pas nécessaire
deinit {
self.tableView.removeObserver(self, forKeyPath: "contentSize")
}
comme @Farthen l'a suggéré, vous devriez toujours appeler votreTableView.layoutIfNeeded () pour recalculer d'abord la taille du contenu.
En appelant layoutIfNeeded, UITableView calculera à nouveau contentSize, puis vous pourrez mettre à jour le cadre ou la constante, quelle qu’elle soit.
Deux lignes simples de code permettront d’économiser beaucoup plus d’efforts.
tableView.layoutIfNeeded()
tableViewHeight.constant = tableView.contentSize.height
Vous pouvez changer le cadre du pied de page. J'appelle avant les apparences animées du pied de page.
if self.newTableView.contentSize.height < self.newTableView.frame.height {
let additionalHeight: CGFloat = self.newTableView.frame.height - self.newTableView.contentSize.height
let tableFooterView = self.newTableView.tableFooterView!
let x = tableFooterView.frame.Origin.x
let y = tableFooterView.frame.Origin.y + additionalHeight
let width = tableFooterView.frame.width
let height = tableFooterView.frame.height
tableFooterView.frame = CGRect(x: x, y: y, width: width, height: height)
}
Cela a fonctionné pour moi, lorsque je résolvais les problèmes de la tableview d'obtenir la bonne taille après avoir ajouté/supprimé des lignes
En utilisant
tableView.layoutIfNeeded()
et mise
tableView.estimatedRowHeight = UITableViewAutomaticDimension