Frage

ich eine App bin zu schaffen, das eine Frage in einem UILabel und einer Multiple-Choice-Antworten angezeigt in UITableView haben wird, zeigt jede Zeile einen Multiple-Choice. Fragen und Antworten variieren, so dass ich diese UITableView muß dynamisch in der Höhe sein.

Ich möchte eine sizeToFit Arbeit um für die Tabelle zu finden. Wo der Rahmen des Tabelle in die Höhe aller festgelegt ist, es ist Inhalt.

Kann mir jemand raten, wie ich das erreichen kann?

War es hilfreich?

Lösung

Eigentlich fand ich die Antwort selbst.

Ich erstelle gerade ein neues CGRect für die tableView.frame mit dem height von table.contentSize.height

Dass setzt die Höhe des UITableView zum height ihres Inhalts. Da der Code ändert die Benutzeroberfläche, vergessen Sie nicht, dass es in dem Haupt-Thread ausgeführt werden:

dispatch_async(dispatch_get_main_queue(), ^{
        //This code will run in the main thread:
        CGRect frame = self.tableView.frame;
        frame.size.height = self.tableView.contentSize.height;
        self.tableView.frame = frame;
    });

Andere Tipps

Swift 5 und 4.2 Lösung ohne KVO, DispatchQueue oder Einstellung Einschränkungen selbst.

Diese Lösung basiert auf Gulz Antwort .

Erstellen

1) eine Unterklasse von UITableView:

import UIKit

final class ContentSizedTableView: UITableView {
    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }
}

2) hinzufügen UITableView zum Layout und Satz Einschränkungen auf allen Seiten. Stellen Sie die Klasse davon ContentSizedTableView.

3) sollten Sie einige Fehler sehen, weil Storyboard nicht unsere Unterklasse intrinsicContentSize berücksichtigen. Dieses Problem beheben, indem die Größe Inspektoren zu öffnen und das Überschreiben die intrinsicContentSize auf einen Platzhalter Wert. Dies ist eine Überschreibung für Design-Zeit. Zur Laufzeit wird es die Überschreibung in unserer ContentSizedTableView Klasse verwenden


Update: Changed Code für Swift 4.2. Wenn Sie mit einer früheren Version, die Verwendung UIViewNoIntrinsicMetric statt UIView.noIntrinsicMetric

Swift Lösung

Folgen Sie

vor:

1- Stellen Sie die Höhe Einschränkung für die Tabelle aus dem Storyboard.

2- Ziehen die Höhenbeschränkung von dem Storyboard und erstellen @IBOutlet es im View-Controller-Datei.

    @IBOutlet weak var tableHeight: NSLayoutConstraint!

3- Dann können Sie die Höhe für die Tabelle ändern dynamicaly mit diesem Code:

override func viewWillLayoutSubviews() {
    super.updateViewConstraints()
    self.tableHeight?.constant = self.table.contentSize.height
}

Aktualisieren

Wenn die letzte Zeile Schnitt für Sie ist, versuchen viewWillLayoutSubviews () in willDisplay Zellfunktion aufzurufen:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}

Ich habe versucht, diese in iOS 7 und es funktionierte für mich

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}

Fügen Sie einen Beobachter für die Content Eigenschaft auf der Tabellenansicht, und stellen Sie die Bildgröße entsprechend

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];

dann in dem Rückruf:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
         CGRect frame = your_tableview.frame;
         frame.size = your_tableview.contentSize;
         your_tableview.frame = frame;
    }

Hope dies wird Ihnen helfen.

Falls Sie nicht möchten, dass der Tabellenansicht des Inhaltsgröße ändert sich verfolgen, könnten Sie diese Unterklasse nützlich finden.

protocol ContentFittingTableViewDelegate: UITableViewDelegate {
    func tableViewDidUpdateContentSize(_ tableView: UITableView)
}

class ContentFittingTableView: UITableView {

    override var contentSize: CGSize {
        didSet {
            if !constraints.isEmpty {
                invalidateIntrinsicContentSize()
            } else {
                sizeToFit()
            }

            if contentSize != oldValue {
                if let delegate = delegate as? ContentFittingTableViewDelegate {
                    delegate.tableViewDidUpdateContentSize(self)
                }
            }
        }
    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        return contentSize
    }
}

Ich hatte einen Tisch Blick in Inneren Ansicht blättern und hatte Tableview die Höhe und die Größe entsprechend zu berechnen. Das sind Schritte, die ich getroffen habe:

0) in eine UIView zu Ihrem Scroll (wahrscheinlich ohne diesen Schritt arbeiten, aber ich habe es mögliche Konflikte zu vermeiden) - dies ist eine containr Ansicht für Ihre Tabellenansicht sein. Wenn Sie diesen Schritt, und stellen Sie die Ansichten Grenzen Recht auf Tableview die diejenigen.

1) Erstellen Sie eine Unterklasse von UITableView:

class IntrinsicTableView: UITableView {

    override var contentSize:CGSize {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        self.layoutIfNeeded()
        return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
    }

}

2) Setklasse einer Tabellenansicht in der Storyboard zu IntrinsicTableView: Screenshot: http://joxi.ru/a2XEENpsyBWq0A

3 die heightConstraint auf den Tisch Ansicht Set)

4) Ziehen Sie die IBOutlet Ihrer Tabelle zu Ihrem Viewcontroller

5) ziehen Sie den IBOutlet Ihrer Tabelle Höhe Einschränkung auf Ihre Viewcontroller

6) fügen Sie diese Methode in Ihre Viewcontroller:

override func viewWillLayoutSubviews() {
        super.updateViewConstraints()
        self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
    }

Hope, das hilft

Swift 3, iOS 10.3

Lösung 1: Gerade self.tableview.sizeToFit() in cellForRowAt indexPath Funktion setzen. Achten Sie darauf, Set Tableview Höhe höher, dann müssen Sie. Dies ist eine gute Lösung, wenn Sie keine Ansichten unter Tableview haben. Wenn Sie jedoch haben, wird unten Tableview-Einschränkung nicht aktualisiert werden (ich habe nicht versucht, es zu beheben, weil ich mit der Lösung 2 kam)

Beispiel:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell {
        cell.configureCell(data: testArray[indexPath.row])
        self.postsTableView.sizeToFit()
        return cell
    }

    return UITableViewCell()
}

Lösung 2: Set Tableview Höhenbeschränkung in Storyboard und ziehen Sie es an die Viewcontroller. Wenn Sie die durchschnittliche Höhe Ihrer Zelle wissen, und Sie wissen, wie viele Elemente das Array enthält, können Sie etwas tun:

tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0     // Let's say 90 is the average cell height

* EDIT:

Nach all den Lösungen, die ich versuchte, und jeder von ihnen war etwas Fixierung, aber nicht vollständig, diesen ist die Antwort, dass Um dieses Problem vollständig erklärt und Korrekturen.

Mimo Antwort und Anooj VM ‚s Antwort beide sind toll, aber es gibt ein kleines Problem, wenn Sie eine große Liste haben, ist es möglich, dass die Höhe des Rahmens werden einige Ihrer Zellen Cutoff.

So. Ich habe die Antwort ein wenig geändert:

dispatch_async(dispatch_get_main_queue()) {
    //This code will run in the main thread:
    CGFloat newHeight=self.tableView.contentSize.height;
    CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y);
    if (newHeight>screenHeightPermissible)
    {
        //so that table view remains scrollable when 'newHeight'  exceeds the screen bounds
        newHeight=screenHeightPermissible;
    }

    CGRect frame = self.tableView.frame;
    frame.size.height = newHeight;
    self.tableView.frame = frame;
}

Es gibt eine viel bessere Möglichkeit, es zu tun, wenn Sie Autolayout verwenden: die Einschränkung ändern, die die Höhe bestimmt. berechnen nur die Höhe des Tabelleninhalte, dann die Einschränkung finden und verändern. Hier ist ein Beispiel (unter der Annahme, dass die Einschränkung, dass Ihre Tabelle Höhe bestimmt ist eigentlich eine Höhe Beschränkung mit Bezug „Equal“):

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    for constraint in tableView.constraints {
        if constraint.firstItem as? UITableView == tableView {
            if constraint.firstAttribute == .height {
                constraint.constant = tableView.contentSize.height
            }
        }
    }
}

Als Erweiterung der Anooj VM Antwort, schlage ich folgendes refresh Inhaltsgröße nur dann, wenn sie sich ändert.

Dieser Ansatz auch deaktivieren Scrollen richtig und unterstützen größere Listen und Rotation . Es besteht keine Notwendigkeit zu dispatch_async weil Content Änderungen auf Hauptthread ausgelöst werden.

- (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 
}


- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize {
        CGRect superviewTableFrame  = self.tableView.superview.bounds;
        CGRect tableFrame = self.tableView.frame;
        BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height;
        tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize;
        [UIView animateWithDuration:0.3
                                    delay:0
                                    options:UIViewAnimationOptionCurveLinear
                                    animations:^{
                            self.tableView.frame = tableFrame;
        } completion: nil];
        self.tableView.scrollEnabled = shouldScroll;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting &&
        [keyPath isEqualToString:@"contentSize"] &&
        !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) {
        [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]];
    } 
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    [self resizeTableAccordingToContentSize:self.tableView.contentSize]; }

- (void)dealloc {
    [self.tableView removeObserver:self forKeyPath:@"contentSize"];
}

objc Version von Musa almatri

(void)viewWillLayoutSubviews
{
    [super updateViewConstraints];
    CGFloat desiredHeight = self.tableView.contentSize.height;
    // clamp desired height, if needed, and, in that case, leave scroll Enabled
    self.tableHeight.constant = desiredHeight;
    self.tableView.scrollEnabled = NO;
}

Sie können versuchen, diese Gewohnheit AGTableView

So legen Sie eine Tableview Höhe Constraint Storyboard verwenden oder programmatisch. (Diese Klasse automatisch eine Höhenbeschränkung und SET Seitenhöhe auf yourtableview Höhe fetch).

class AGTableView: UITableView {

    fileprivate var heightConstraint: NSLayoutConstraint!

    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.associateConstraints()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.associateConstraints()
    }

    override open func layoutSubviews() {
        super.layoutSubviews()

        if self.heightConstraint != nil {
            self.heightConstraint.constant = self.contentSize.height
        }
        else{
            self.sizeToFit()
            print("Set a heightConstraint to Resizing UITableView to fit content")
        }
    }

    func associateConstraints() {
        // iterate through height constraints and identify

        for constraint: NSLayoutConstraint in constraints {
            if constraint.firstAttribute == .height {
                if constraint.relation == .equal {
                    heightConstraint = constraint
                }
            }
        }
    }
}

Hinweis Wenn irgendein Problem eine Höhe einstellen dann yourTableView.layoutSubviews().

Basierend auf Antwort von fl034 . Aber für Xamarin.iOS Benutzer:

    [Register("ContentSizedTableView")]
    public class ContentSizedTableView : UITableView
    {
        public ContentSizedTableView(IntPtr handle) : base(handle)
        {
        }

        public override CGSize ContentSize { get => base.ContentSize; set { base.ContentSize = value; InvalidateIntrinsicContentSize(); } }
        public override CGSize IntrinsicContentSize
        {
            get
            {
                this.LayoutIfNeeded();
                return new CGSize(width: NoIntrinsicMetric, height: ContentSize.Height);
            }
        }
    }

Wenn Sie Ihr Tisch wollen dynamisch sein, benötigen Sie eine Lösung auf dem Tabelleninhalt Basis zu verwenden, wie oben detailliert beschrieben. Wenn Sie einfach eine kleinere Tabelle anzeigen möchten, können Sie einen Container Ansicht verwenden und einbetten UITableViewController in ihm - die UITableView wird entsprechend der Behältergröße geändert werden.

Dies vermeidet eine Menge von Berechnungen und Anrufe an das Layout.

Mu Lösung für diese in schnellen 3 : Rufen Sie diese Methode in viewDidAppear

func UITableView_Auto_Height(_ t : UITableView)
{
        var frame: CGRect = t.frame;
        frame.size.height = t.contentSize.height;
        t.frame = frame;        
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top