Изменение размера UITableView для соответствия содержимому
Я создаю приложение, которое будет иметь вопрос в UILabel
и ответы с несколькими вариантами ответов, отображаемые в UITableView
, каждая строка показывает множественный выбор. Вопросы и ответы будут меняться, поэтому мне нужно, чтобы этот UITableView
был динамическим по высоте.
Я хотел бы найти работу sizeToFit
для таблицы. Если рамка таблицы установлена на высоту всего содержимого.
Может ли кто-нибудь посоветовать, как я могу это достичь?
Ответы
Ответ 1
На самом деле я сам нашел ответ.
Я просто создаю новый CGRect
для tableView.frame
с height
из table.contentSize.height
Это устанавливает высоту UITableView
в height
ее содержимого.
Поскольку код изменяет пользовательский интерфейс, не забудьте запустить его в основном потоке:
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;
});
Ответ 2
Решение Swift 5 и 4.2 без KVO, DispatchQueue или установки ограничений самостоятельно.
Это решение основано на ответе Гульца.
1) Создайте подкласс 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) Добавьте UITableView
к вашему макету и установите ограничения со всех сторон. Установите его класс ContentSizedTableView
.
3) Вы должны увидеть некоторые ошибки, потому что Storyboard не учитывает intrinsicContentSize
нашего подкласса. Исправьте это, открыв инспектор размера и переопределив intrinsicContentSize для значения заполнителя. Это переопределение для времени разработки. Во время выполнения он будет использовать переопределение в нашем классе ContentSizedTableView
Обновление: изменен код для Swift 4.2. Если вы используете предыдущую версию, используйте UIViewNoIntrinsicMetric
вместо UIView.noIntrinsicMetric
Ответ 3
Быстрое решение
Следуй этим шагам:
1- Установите ограничение высоты таблицы для раскадровки.
2- Перетащите ограничение высоты из раскадровки и создайте @IBOutlet для него в файле контроллера вида.
@IBOutlet weak var tableHeight: NSLayoutConstraint!
3- Затем вы можете изменить высоту таблицы динамически с помощью этого кода:
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.tableHeight?.constant = self.table.contentSize.height
}
Обновить
Если последняя строка вырезана для вас, попробуйте вызвать viewWillLayoutSubviews() в функции ячейки viewDisplay:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.viewWillLayoutSubviews()
}
Ответ 4
Я пробовал это в iOS 7, и это сработало для меня
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView sizeToFit];
}
Ответ 5
Добавить наблюдателя для свойства contentSize в представлении таблицы и соответствующим образом скорректировать размер кадра
[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL];
то в обратном вызове:
- (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;
}
Надеюсь, это поможет вам.
Ответ 6
Если вы не хотите самостоятельно отслеживать изменения размера содержимого таблицы, вы можете найти этот подкласс полезным.
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
У меня было табличное представление в представлении прокрутки и я должен был вычислить высоту tableView и соответственно изменить ее размер. Вот шаги, которые я предпринял:
0) добавьте UIView в ваш scrollView (возможно, он будет работать без этого шага, но я сделал это, чтобы избежать возможных конфликтов) - это будет представление контейнеров для вашего табличного представления. Если вы сделаете этот шаг, то установите границы представлений прямо на таблицы.
1) создать подкласс 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) установить класс табличного представления в раскадровке как IntrinsicTableView: снимок экрана: http://joxi.ru/a2XEENpsyBWq0A
3) Установите высоту ограничения для вашего вида таблицы
4) перетащите IBoutlet вашей таблицы на ваш ViewController
5) перетащите IBoutlet вашего ограничения высоты таблицы в ваш ViewController
6) добавьте этот метод в ваш ViewController:
override func viewWillLayoutSubviews() {
super.updateViewConstraints()
self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height
}
Надеюсь это поможет
Ответ 8
В случае, если ваш contentSize не прав, это потому, что он основан на оценочной RowHeight (автоматически), используйте это до
tableView.estimatedRowHeight = 0;
источник: https://forums.developer.apple.com/thread/81895
Ответ 9
Swift 3, iOS 10.3
Решение 1:
Просто поставьте self.tableview.sizeToFit()
в cellForRowAt indexPath
функцию. Не забудьте установить высоту стола выше, чем вам нужно.
Это хорошее решение, если у вас нет представлений ниже таблицы. Однако, если у вас есть, нижнее ограничение таблицы не будет обновляться (я не пытался его исправить, потому что я придумал решение 2)
Пример:
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()
}
Решение 2:
Установите ограничение высоты таблицы в раскадровке и перетащите ее в ViewController. Если вы знаете среднюю высоту своей ячейки и знаете, сколько элементов содержит ваш массив, вы можете сделать что-то вроде этого:
tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0 // Let say 90 is the average cell height
* EDIT:
После всех решений, которые я пробовал, и каждый из них исправлял что-то, но не полностью, этот является ответом, который полностью объясняет и устраняет эту проблему.
Ответ 10
Ответ Mimo и Ответ Anooj VM оба являются удивительными, но есть небольшая проблема, если у вас есть большой список, возможно, что высота кадра отключит некоторые из ваших ячеек.
Итак. Я немного изменил ответ:
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;
}
Ответ 11
Существует намного лучший способ сделать это, если вы используете AutoLayout: измените ограничение, определяющее высоту. Просто вычислите высоту содержимого вашей таблицы, затем найдите ограничение и измените его. Вот пример (если предположить, что ограничение, определяющее высоту таблицы, на самом деле является ограничителем высоты с отношением "Равно" ):
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
}
}
}
}
Ответ 12
objc версия 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;
}
Ответ 13
Вы можете попробовать этот пользовательский AGTableView
Установка ограничения высоты таблицы TableView с помощью раскадровки или программным способом. (Этот класс автоматически выбирает ограничение высоты и устанавливает высоту представления контента на высоту вашего стола).
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
}
}
}
}
}
Примечание. Если yourTableView.layoutSubviews()
проблема с установкой высоты, то yourTableView.layoutSubviews()
.
Ответ 14
Как расширение ответа Anooj VM, я предлагаю следующее обновить размер содержимого только тогда, когда он изменится.
Этот подход также отключает прокрутку и поддерживает более крупные списки и ротация. Нет необходимости dispatch_async, потому что изменения contentSize отправляются в основном потоке.
- (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"];
}
Ответ 15
Решение Mu для этого в swift 3. Вызовите этот метод в viewDidAppear
func UITableView_Auto_Height(_ t : UITableView)
{
var frame: CGRect = t.frame;
frame.size.height = t.contentSize.height;
t.frame = frame;
}
Ответ 16
Задайте свойства вида таблицы для
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100
И в ячейке таблицы со numberOfLines = 0
вашего свойства метки numberOfLines = 0
установите верхние, нижние, левые и правые ограничения на верхнюю, нижнюю, левую и правую границы элементов. ** Он автоматически рассчитает высоту