2013-06-27 3 views
47

На данный момент я использую UITableView вместе с другими представлениями, которые содержатся в файле UIScrollView. Я хочу, чтобы высота UITableView была такой же, как и ее высота содержимого.UITableView в UIScrollView с использованием автозапуска

Чтобы усложнить ситуацию, я также вставляю/удаляю строки, чтобы обеспечить эффект аккордеона, так что когда пользователь нажимает на строку, он будет показывать более подробную информацию для этой строки.

У меня есть вставка/удаление сделано, хотя на данный момент он не обновляет UIScrollView, который является его SuperView так, чтобы размер содержимого UIScrollView пересчитывается и UITableView наряду с другими видами в UIScrollView являются отображается правильно.

Как я могу реализовать это, чтобы отрегулировать размер UIScrollView, а его содержимое правильно выложено при изменении содержимого UITableView? В настоящее время я использую автоматическую компоновку.

+0

вы добавляете UITableView в UIScrollView ????? – iPatel

+0

Да, UITableView не занимает всю видимую область. Мне хорошо известно, что UITableView имеет UIScrollView. Чтобы отключить эту прокрутку, я устанавливаю высоту tableView в contentSize. –

+2

UITableView сам имеет scrollview. Тогда зачем добавлять в другой scrollView? – Meera

ответ

83

Прежде всего, это те другие виды (братья и сестры таблицы) строго выше и ниже табличного вида? Если да, рассмотрели ли вы возможность позволить прокрутку таблицы в обычном режиме и помещать эти внешние представления в представления заголовка и нижнего колонтитула таблицы? Тогда вам не потребуется прокрутка.

Во-вторых, вы можете прочитать Technical Note TN2154: UIScrollView And Autolayout, если вы еще этого не сделали.

В-третьих, учитывая информацию в этой технической записке, я могу придумать несколько способов сделать то, что вы хотите. Самый чистый - это, вероятно, создание подкласса UITableView, который реализует метод intrinsicContentSize. Реализация тривиальна:

@implementation MyTableView 

- (CGSize)intrinsicContentSize { 
    [self layoutIfNeeded]; // force my contentSize to be updated immediately 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 

@end 

Затем просто дайте автомасштабированию использовать собственный размер содержимого таблицы. Создайте ограничения между подзонами представления прокрутки (включая табличное представление), чтобы их выложить, и убедитесь, что есть ограничения для всех четырех краев прокрутки.

Возможно, вам понадобится отправить invalidateIntrinsicContentSize на вид таблицы в соответствующие моменты времени (при добавлении или удалении строк или изменении высоты строк). Вероятно, вы можете просто переопределить соответствующие методы в MyTableView, чтобы сделать это. Например. делать [self invalidateIntrinsicContentSize] в -endUpdates, -reloadData, - insertRowsAtIndexPaths:withRowAnimation: и т.д.

Вот результат моего тестирования:

table view with intrinsic content size in scroll view

Вид прокрутки имеет светло-голубой фон. Красная верхняя метка и синяя нижняя метка являются братьями и сестрами вида таблицы внутри прокрутки.

Вот полный исходный код контроллера вида в моем тесте. Нет xib-файла.

#import "ViewController.h" 
#import "MyTableView.h" 

@interface ViewController() <UITableViewDataSource, UITableViewDelegate> 

@end 

@implementation ViewController 

- (void)loadView { 
    UIView *view = [[UIView alloc] init]; 
    self.view = view; 

    UIScrollView *scrollView = [[UIScrollView alloc] init]; 
    scrollView.translatesAutoresizingMaskIntoConstraints = NO; 
    scrollView.backgroundColor = [UIColor cyanColor]; 
    [view addSubview:scrollView]; 

    UILabel *topLabel = [[UILabel alloc] init]; 
    topLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    topLabel.text = @"Top Label"; 
    topLabel.backgroundColor = [UIColor redColor]; 
    [scrollView addSubview:topLabel]; 

    UILabel *bottomLabel = [[UILabel alloc] init]; 
    bottomLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    bottomLabel.text = @"Bottom Label"; 
    bottomLabel.backgroundColor = [UIColor blueColor]; 
    [scrollView addSubview:bottomLabel]; 

    UITableView *tableView = [[MyTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; 
    tableView.translatesAutoresizingMaskIntoConstraints = NO; 
    tableView.dataSource = self; 
    tableView.delegate = self; 
    [scrollView addSubview:tableView]; 

    UILabel *footer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 
    footer.backgroundColor = [UIColor greenColor]; 
    footer.text = @"Footer"; 
    tableView.tableFooterView = footer; 

    NSDictionary *views = NSDictionaryOfVariableBindings(
     scrollView, topLabel, bottomLabel, tableView); 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|[scrollView]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[scrollView]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|[topLabel][tableView][bottomLabel]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[topLabel]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|-8-[tableView]-8-|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraint:[NSLayoutConstraint 
     constraintWithItem:tableView attribute:NSLayoutAttributeWidth 
     relatedBy:NSLayoutRelationEqual 
     toItem:view attribute:NSLayoutAttributeWidth 
     multiplier:1 constant:-16]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[bottomLabel]|" 
     options:0 metrics:nil views:views]]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return 20; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 
    if (!cell) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; 
    } 
    cell.textLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row]; 
    return cell; 
} 

@end 
+5

** Важное примечание: ** для подведения итогов требуется нижний колонтитул стола! (потерял один час с ним -) – AncAinu

+4

Спасибо за отличный ответ! Сэкономил мне часы! Я создал сущность подкласса (он работает без верхних и нижних колонтитулов): https://gist.github.com/booiiing/7941890 –

+1

Это работает очень хорошо, за исключением анимированных изменений размера контента, где tableViews размер изменится только после завершения анимации внутри tableView – Ahti

44

В дополнение к ответу Роба есть скор пример самостоятельного изменяемыми подкласса UITableView:

Swift 2.x

class IntrinsicTableView: UITableView { 

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


    override func intrinsicContentSize() -> CGSize { 
     self.layoutIfNeeded() 
     return CGSizeMake(UIViewNoIntrinsicMetric, contentSize.height) 
    } 

} 

Swift 3.x или Swift 4.х

class IntrinsicTableView: UITableView { 

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

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

} 

Я использовал его, чтобы поместить вид таблицы в ячейку другой авто-изменяемыми табличного представления.

+0

Я пытаюсь записать этот метод в swift 3 переопределить func intrinsicContentSize() , но ошибка отображается -> метод не переопределяет любой из суперкласса –

+6

Swift 3 заменил эту функцию в пользу: переопределить var intrinsicContentSize: CGSize –

8

Описание obj-C. Он основан на решении от пользователя @MuHAOS

@implementation SizedTableView 

- (void)setContentSize:(CGSize)contentSize { 
    [super setContentSize:contentSize]; 
    [self invalidateIntrinsicContentSize]; 
} 

- (CGSize)intrinsicContentSize { 
    [self layoutIfNeeded]; // force my contentSize to be updated immediately 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 


@end 
+0

как мы можем сделать это с раскадровкой –

+1

@AmrAngry сделать ваш класс tableview равным SizedTableView –

+0

Это должно быть отмеченным как идеальный ответ. – Nil

1

@ MuHAOS х и @ Klemen-Žagar код помог мне много, но на самом деле вызывает проблемы производительности, вызывая бесконечный цикл компоновки, когда TableView содержится в представлении стека, который сам содержится в виде прокрутки. См. Мое решение ниже.

@interface AutoSizingTableView() 
@property (nonatomic, assign) BOOL needsIntrinsicContentSizeUpdate; 
@end 

@implementation AutoSizingTableView 

- (void)setContentSize:(CGSize)contentSize 
{ 
    [super setContentSize:contentSize]; 

    self.needsIntrinsicContentSizeUpdate = YES; 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     if (!self.needsIntrinsicContentSizeUpdate) { 
      return; 
     } 

     self.needsIntrinsicContentSizeUpdate = NO; 
     [self layoutIfNeeded]; 
     [self invalidateIntrinsicContentSize]; 
    }); 
} 

- (CGSize)intrinsicContentSize 
{ 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 

@end 
0

Вы можете добавить представление как headerview и footerview tableview. потому что tableview является подпунктом scrollview. нижеприведенный пример.

UILabel *topLabel = [[UILabel alloc] init]; 
topLabel.translatesAutoresizingMaskIntoConstraints = NO; 
topLabel.text = @"Top Label"; 
topLabel.backgroundColor = [UIColor redColor]; 
tableView.tableFooterView = topLabel; 

UILabel *footer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 
    footer.backgroundColor = [UIColor greenColor]; 
    footer.text = @"Footer"; 
    tableView.tableFooterView = footer; 

, а также вы можете добавить headerview и footerview из Tableview с помощью простого перетаскивания вид на Tableview в раскадровке и принять IBOutlet этого мнения.

Смежные вопросы