UITableView w UIScrollView przy użyciu autolayout
W tej chwili używam UITableView
wraz z innymi poglądami, które są zawarte w UIScrollView
. Chcę, aby UITableView
miała taką samą wysokość jak jej wysokość zawartości.
Aby skomplikować sprawy, wstawiam / usuwam wiersze, aby uzyskać efekt akordeonu, aby gdy użytkownik dotknie wiersza, wyświetli więcej szczegółów dla tego wiersza.
Mam wstawianie / usuwanie zrobione, choć w tej chwili nie aktualizuje UIScrollView który jest jego superview tak aby Rozmiar zawartości UIScrollView
jest przeliczany, a {[0] } wraz z innymi widokami w UIScrollView
są wyświetlane poprawnie.
Jak mogę to zaimplementować, aby Rozmiar UIScrollView
był dopasowany i prawidłowo ułożony, gdy zmieniam zawartość UITableView
? Obecnie używam układu auto.
5 answers
Po pierwsze, czy te inne widoki (rodzeństwo widoku tabeli) są ściśle powyżej i poniżej widoku tabeli? Jeśli tak, czy rozważałeś możliwość normalnego przewijania widoku tabeli i umieszczenie tych widoków zewnętrznych w widoku nagłówka i stopki widoku tabeli? Wtedy nie potrzebujesz widoku przewijania.
Po drugie, możesz przeczytać notatkę techniczną TN2154: UIScrollView i Autolayout Jeśli jeszcze tego nie zrobiłeś.
Po trzecie, biorąc pod uwagę informacje w tej notce technicznej, myślę, że kilka sposobów na to, co chcesz. Najczystszym jest prawdopodobnie stworzenie podklasy UITableView
, która implementuje metodę intrinsicContentSize
. Implementacja jest trywialna:
@implementation MyTableView
- (CGSize)intrinsicContentSize {
[self layoutIfNeeded]; // force my contentSize to be updated immediately
return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height);
}
@end
Następnie pozwól układowi automatycznemu użyć wewnętrznego rozmiaru zawartości widoku tabeli. Utwórz ograniczenia między podglądami podrzędnymi widoku przewijania (w tym widoku tabeli), aby je ułożyć, i upewnij się, że istnieją ograniczenia dla wszystkich czterech krawędzi widoku przewijania.
Prawdopodobnie musisz wysłać invalidateIntrinsicContentSize
do widoku tabeli w odpowiednie czasy (Podczas dodawania lub usuwania wierszy lub zmiany wysokości wierszy). Prawdopodobnie możesz po prostu zastąpić odpowiednie metody w MyTableView
, aby to zrobić. Np. do [self invalidateIntrinsicContentSize]
W -endUpdates
, -reloadData
, - insertRowsAtIndexPaths:withRowAnimation:
, itd.
Oto wynik moich testów:
Widok przewijania ma jasnoniebieskie tło. Czerwona górna etykieta i niebieska dolna etykieta są rodzeństwem widoku tabeli w widoku przewijania.
Oto Pełny kod źródłowy widoku kontroler w moim teście. Nie ma pliku 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
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-06-27 06:17:19
Oprócz odpowiedzi Roba istnieje szybki przykład podklasy self-resizable z 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 lub Swift 4.x
class IntrinsicTableView: UITableView {
override var contentSize:CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
}
}
Użyłem go do umieszczenia widoku tabeli w innej komórce widoku tabeli z możliwością automatycznej zmiany rozmiaru.
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-12-11 11:45:19
Oto wersja obj-C. Jest oparty na rozwiązaniu od użytkownika @ 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
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-08-06 09:58:23
Kod@muhaos i @klemen-zagar bardzo mi pomógł, ale w rzeczywistości powoduje problem z wydajnością, uruchamiając niekończącą się pętlę układu, gdy Widok tableview jest zawarty w widoku stosu, który sam jest zawarty w widoku przewijania. Zobacz moje rozwiązanie poniżej.
@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
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-08-12 11:04:00
Możesz dodać Widok jako widok nagłówka i widok stopki tableview. ponieważ Widok tableview jest podglądem podrzędnym widoku przewijania. wykonaj poniższy przykład.
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;
A także możesz dodać Widok nagłówka i stopki tableview za pomocą prostego widoku przeciągnij i upuść do widoku tableview w storyboard i weź IBOutlet tego widoku.
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-09-30 05:07:35