Zmiana rozmiaru UITableView w celu dopasowania zawartości

Tworzę aplikację, która będzie miała pytanie w {[0] } i odpowiedzi wielokrotnego wyboru wyświetlane w UITableView, każdy wiersz pokazuje wielokrotnego wyboru. Pytania i odpowiedzi będą się różnić, więc potrzebuję tego UITableView, aby być dynamicznym w wysokości.

Chciałbym znaleźć sizeToFit pracę wokół stołu. Gdzie ramka tabeli jest ustawiona na wysokość całej jej zawartości.

Czy ktoś może doradzić jak Mogę to osiągnąć?
Author: Brian, 2010-04-07

15 answers

Właściwie to sam znalazłem odpowiedź.

Po prostu tworzę Nowy CGRect dla tableView.frame z height z table.contentSize.height

, który ustawia wysokość UITableView na height jego zawartości. Ponieważ kod modyfikuje interfejs użytkownika, nie zapomnij uruchomić go w głównym wątku:

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;
    });
 138
Author: MiMo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-03 20:48:43

Swift Solution

Wykonaj następujące kroki:

1-Ustaw ograniczenie wysokości stołu z storyboardu.

2-przeciągnij ograniczenie wysokości ze storyboardu i utwórz dla niego @IBOutlet w pliku kontrolera widoku.

    @IBOutlet weak var tableHeight: NSLayoutConstraint!

3 - wtedy możesz dynamicznie zmienić wysokość tabeli używając tego kodu:

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

Update

Jeśli ostatni wiersz jest wycięty dla ciebie, spróbuj wywołać viewwilllayoutsubviews () w komórce willDisplay funkcja:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.viewWillLayoutSubviews()
}
 35
Author: Musa almatri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 03:01:00

Swift 4 rozwiązanie bez KVO, DispatchQueue, samodzielne Ustawianie ograniczeń. Rozwiązanie to opiera się na odpowiedzi Gulza.

1) Utwórz podklasę 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) dodaj UITableView do układu i ustaw ograniczenia ze wszystkich stron. Ustaw jego klasę na IntrinsicTableView.

3) Powinieneś zobaczyć kilka błędów, ponieważ Storyboard nie bierze pod uwagę naszej podklasy ' intrinsicContentSize. Napraw to, otwierając Inspektora rozmiaru i nadpisując intrinsicContentSize do elementu zastępczego wartość. To jest obejście na czas projektowania. W czasie wykonywania użyje obejścia w naszej klasie IntrinsicTableView

 24
Author: fl034,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-25 14:13:16

Próbowałem tego w iOS 7 i zadziałało dla mnie

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView sizeToFit];
}
 19
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-24 15:21:05

Dodaj obserwator dla właściwości contentSize w widoku tabeli i odpowiednio dostosuj rozmiar ramki

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

Następnie w wywołaniu zwrotnym:

- (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;
    }
Mam nadzieję, że to ci pomoże.
 15
Author: Anooj VM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-21 05:15:03

Jeśli nie chcesz śledzić zmian rozmiaru zawartości widoku tabeli, ta podklasa może okazać się przydatna.

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
    }
}
 7
Author: xinatanil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-26 12:08:38

Miałem widok tabeli wewnątrz widoku przewijania i musiałem obliczyć wysokość tableView i odpowiednio zmienić jego rozmiar. To są kroki, które podjąłem:

0) dodaj UIView do widoku przewijania (prawdopodobnie będzie działać bez tego kroku, ale zrobiłem to, aby uniknąć ewentualnych konfliktów) - będzie to Widok containr dla widoku tabeli. Jeśli wykonasz ten krok, Ustaw obramowania widoków bezpośrednio na obramowania tableview.

1) Utwórz podklasę 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) ustawia klasę widoku tabeli w Storyboard to IntrinsicTableView: screenshot: http://joxi.ru/a2XEENpsyBWq0A

3) Ustaw heightConstraint do widoku tabeli

4) przeciągnij IBoutlet tabeli do kontrolera ViewController

5) przeciągnij iboutlet ograniczenia wysokości tabeli do kontrolera ViewController

6) Dodaj tę metodę do kontrolera ViewController:

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

Hope this helps

 4
Author: Gulz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-02 10:04:55

Swift 3, iOS 10.3

Rozwiązanie 1: Wystarczy umieścić self.tableview.sizeToFit() w funkcji cellForRowAt indexPath. Upewnij się, że ustawisz wysokość tableview wyżej niż potrzebujesz. Jest to dobre rozwiązanie, jeśli nie masz widoków poniżej tableview. Jeśli jednak masz, ograniczenie bottom tableview nie zostanie zaktualizowane (nie próbowałem tego naprawić, ponieważ wymyśliłem rozwiązanie 2)

Przykład:

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()
}

Rozwiązanie 2: Ustaw ograniczenie wysokości tableview w storyboard i przeciągnij go do ViewController. Jeśli znasz średnią wysokość komórki i wiesz, ile elementów zawiera tablica, możesz zrobić coś takiego:

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

*EDIT:

Po wszystkich rozwiązaniach próbowałem i każdy z nich coś naprawiał, ale nie do końca, to jest odpowiedzią, która wyjaśnia i rozwiązuje ten problem całkowicie.

 2
Author: Đorđe Nilović,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 09:16:07

Mimo 's answer i anooj VM' s answer obie są niesamowite, ale jest mały problem, jeśli masz dużą listę, możliwe, że wysokość ramki odetnie niektóre z twoich komórek.

Więc. Trochę zmodyfikowałem ODPOWIEDŹ:
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;
}
 1
Author: SandeepAggarwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:05

Jest o wiele lepszy sposób, aby to zrobić, jeśli używasz AutoLayout: Zmień ograniczenie, które określa wysokość. Wystarczy obliczyć wysokość zawartości tabeli, a następnie znaleźć ograniczenie I zmienić je. Oto przykład (zakładając, że ograniczenie, które określa wysokość tabeli, jest w rzeczywistości ograniczeniem wysokości z relacją "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
            }
        }
    }
}
 1
Author: ChrisB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-09 09:09:30

W przypadku, gdy zawartość nie jest prawidłowa, ponieważ opiera się na estymatedrowheight (automatic), użyj tego przed

TableView.estimatedRowHeight = 0;

Źródło: https://forums.developer.apple.com/thread/81895

 1
Author: Yohan Dahmani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 11:45:34

Objc wersja 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;
}
 0
Author: Anton Tropashko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 11:57:34

Możesz wypróbować ten Custom AGTableView

Aby ustawić ograniczenie wysokości TableView za pomocą storyboard lub programowo. (Ta klasa automatycznie pobiera ograniczenie wysokości i ustawia wysokość widoku zawartości na wysokość yourtableview).

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
                }
            }
        }
    }
}

Uwaga jeśli jakiś problem z ustawieniem wysokości to yourTableView.layoutSubviews().

 0
Author: AshvinGudaliya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-31 05:28:55

Jako rozszerzenie odpowiedzi ANOOJ VM, proponuję aby odświeżyć Rozmiar zawartości tylko wtedy, gdy się zmieni.

To podejście również wyłącza prawidłowe przewijanie i obsługuje większe listy i rotacja. Nie ma potrzeby dispatch_async, ponieważ zmiany contentSize są wysyłane w głównym wątku.

- (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"];
}
 -1
Author: Ramiro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-25 15:31:01

Rozwiązanie Mu w swift 3 : wywołanie tej metody w viewDidAppear

func UITableView_Auto_Height(_ t : UITableView)
{
        var frame: CGRect = t.frame;
        frame.size.height = t.contentSize.height;
        t.frame = frame;        
}
 -1
Author: brahimm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 18:05:22