web-dev-qa-db-fra.com

Quand est-ce que contentSize d'un UITableView est défini?

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.

44
Darren

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 {}
}
69
felinira

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"];
}
24
Brian Sachetta

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;
}
14
rob mayoff
  1. Ajouter un observateur (dans mon échantillon dans viewDidLoad

    tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
    
  2. 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
                }
            }
        }
    }
    
  3. Retirer l'observateur lorsqu'il n'est pas nécessaire

    deinit {
        self.tableView.removeObserver(self, forKeyPath: "contentSize")
    }
    
6
gbk

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
1
Anil Kukadeja

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)
    }
0
Charles Bessonnet

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
0
RiceAndBytes