Я пытаюсь реализовать представление таблицы, которое позволяет пользователю отображать больше строк, чтобы переключать полное количество строк или меньшее количество строк. У меня есть все данные заранее, когда представление загружено, поэтому мне не нужно извлекать какие-либо дополнительные данные.
Я могу заставить его работать, но проблема, с которой я сталкиваюсь, заключается в том, что мое табличное представление не плавно анимируется при расширении или сворачивании. Что происходит, так это то, что если активируется действие «Показать больше», размер таблицы сразу обновляется до полной высоты таблицы со всеми данными в ней. Тогда строки будут анимированы.
Аналогичным образом при скрытии строк высота таблицы сразу уменьшится до конечной высоты, а затем строки будут анимированы.
Вот картина того, что происходит. Он просто прыгает на полную высоту, а затем анимирует ряды. Но я хотел бы, чтобы он плавно увеличивал высоту таблицы, раскрывая данные по мере того, как она плавно расширялась вниз. Хотелось бы наоборот, где плавно скользит вверх при нажатии показать меньше.
Мое приложение выглядит следующим образом:
UIScrollView
UIStackView
UIViewController
UIViewController
UITableView
‹-- раздел, над которым я работаю здесьUIView
- ...
По сути, у меня есть прокручиваемый список разделов разных данных. Некоторые разделы представляют собой таблицы, некоторые представляют собой просто специальные представления, организованные с помощью AutoLayout, другие имеют представления коллекции или контроллеры представления страницы или другие типы представлений.
Но этот раздел представлен UITableView в предыдущем списке.
#import "MyTableView.h"
#import "MyAutosizingTableView.h"
@interface MyTableView ()
@property (strong, nonatomic) UILabel *titleLabel;
@property (strong, nonatomic) MyAutosizingTableView *tableView;
@end
@implementation MyTableView
- (instancetype)init {
return [self initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (void)initialize {
[self.titleLabel setText:@"Details"];
self.numberOfRows = 3;
[self addSubview:self.titleLabel];
[self addSubview:self.tableView];
[NSLayoutConstraint activateConstraints:@[
[self.titleLabel.leadingAnchor constraintEqualToAnchor:self.layoutMarginsGuide.leadingAnchor],
[self.titleLabel.topAnchor constraintEqualToAnchor:self.layoutMarginsGuide.topAnchor],
[self.titleLabel.trailingAnchor constraintEqualToAnchor:self.layoutMarginsGuide.trailingAnchor],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[self.tableView.topAnchor constraintEqualToSystemSpacingBelowAnchor:self.titleLabel.bottomAnchor multiplier:1.0f],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[self.tableView.widthAnchor constraintEqualToAnchor:self.widthAnchor]
]];
}
- (UITableView *)tableView {
if (!self->_tableView) {
self->_tableView = [[MyAutosizingTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self->_tableView.translatesAutoresizingMaskIntoConstraints = NO;
self->_tableView.rowHeight = UITableViewAutomaticDimension;
self->_tableView.estimatedRowHeight = UITableViewAutomaticDimension;
self->_tableView.allowsSelection = NO;
self->_tableView.scrollEnabled = NO;
self->_tableView.delegate = self;
self->_tableView.dataSource = self;
[self->_tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:@"dataCell"];
}
return self->_tableView;
}
- (UILabel *)titleLabel {
if (!self->_titleLabel) {
self->_titleLabel = [[UILabel alloc] init];
self->_titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self->_titleLabel.numberOfLines = 0;
self->_titleLabel.userInteractionEnabled = YES;
self->_titleLabel.textAlignment = NSTextAlignmentNatural;
self->_titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
self->_titleLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;
self->_titleLabel.adjustsFontSizeToFitWidth = NO;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showMore)];
[self->_titleLabel addGestureRecognizer:tapGesture];
}
return self->_titleLabel;
}
- (void)showMore {
if (self.numberOfRows == 0) {
self.numberOfRows = 3;
} else {
self.numberOfRows = 0;
}
NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:0];
[self.tableView reloadSections:indexes withRowAnimation:UITableViewRowAnimationFade];
}
- (void)setData:(NSArray<NSString *> *)data {
self->_data = data;
[self.tableView reloadData];
}
- (void)didMoveToSuperview {
//this has no effect unless the view is already in the view hierarchy
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.numberOfRows <= 0) {
return self.data.count;
}
return MIN(self.data.count, self.numberOfRows);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *data = self.data[indexPath.row];
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"dataCell" forIndexPath:indexPath];
cell.data = data;
return cell;
}
@end
У меня есть подкласс UITableView, который я использовал в предыдущем коде. Причина, по которой у меня есть подкласс табличного представления, заключается в том, чтобы изменить размер таблицы при изменении содержимого. Если кто-нибудь знает лучший способ сделать это без подкласса, мне было бы очень интересно это узнать.
#import "MyAutosizingTableView.h"
@implementation MyAutosizingTableView
- (CGSize)intrinsicContentSize {
return self.contentSize;
}
- (void)setContentSize:(CGSize)contentSize {
[super setContentSize:contentSize];
[self invalidateIntrinsicContentSize];
}
@end
Кто-нибудь знает, что я могу сделать, чтобы получить плавную анимацию расширения? Мне бы очень хотелось, чтобы таблица плавно расширялась и показывала данные, находящиеся в новых строках.
Обновление - общий обзор того, что я пытаюсь сделать
Здесь я попытаюсь описать, чего я пытаюсь достичь и как я это делаю, поэтому, если у кого-то есть какие-либо альтернативные подходы или улучшения для изложения этого, я был бы очень открыт для предложений. Заранее спасибо за то, что прочитали это.
Итак, я работаю над контроллером представления, который отображает данные о продукте, например, представьте себе автомобиль. Контроллер представления имеет разные секции, отвечающие за отображение разных данных. Например, в первом разделе отображаются изображения товара, а для этого раздела я использую UIPageView, который отображает карусель изображений товаров.
В другом разделе отображаются параметры текущего продукта. Например, кто-то может выбрать другой цвет для машины или другие колеса. Для этого раздела я использую табличное представление для отображения списка доступных атрибутов, где каждый атрибут находится в другом разделе таблицы. При нажатии на заголовок раздела в виде таблицы добавляется строка, в которой отображаются доступные параметры для этого атрибута. Например, предположим, что у автомобиля есть разные цвета (красный, зеленый, синий и желтый). При нажатии на заголовок раздела табличное представление добавляет строку и анимирует ее (используя метод, описанный в главе 8 «Программирование iOS 12»). Затем показанная строка содержит UICollectionView, который прокручивается горизонтально, позволяя пользователю выбирать между цветами (или параметрами колеса или любым другим изменяемым атрибутом).
В другом разделе показано, что другие покупатели говорят об этом продукте. Например, если кто-то оставит отзыв об автомобиле, он будет размещен в этом разделе. В этом разделе есть таблица, показывающая, как продукт оценивается по разным критериям. Используя пример с автомобилем, у него может быть ряд по комфорту, другой по расходу топлива, третий по производительности и так далее. Также есть горизонтальный UICollectionView, отображающий отзывы о продукте.
Еще один раздел представляет собой список атрибутов продукта. Например, для автомобиля слева может быть указан объем двигателя, а справа — V12.
И есть и другие разделы, но затем, чтобы связать их все вместе, у меня есть представление прокрутки с вертикальным UIStackView внутри него. И вот что мне действительно интересно. Как лучше всего отображать или размещать все эти разделы? Является ли представление стека подходящим способом, или я должен использовать табличное представление, или мне просто нужно иметь представление прокрутки с этими представлениями, связанными вместе, просто используя AutoLayout напрямую, или есть какой-то лучший способ сделать это, чем все это?
Одна вещь, которая очень важна, заключается в том, что каждая секция может быть разных размеров для разных продуктов. Например, некоторые секции могут иметь одну высоту для одного продукта, но совершенно другую высоту для других продуктов. Поэтому мне нужно, чтобы он мог динамически изменять размер каждого раздела, а также мне нужно иметь возможность анимировать некоторые изменения размера (например, раздел, в котором он добавляет строку в таблицу, а затем удаляет ее, который необходимо анимировать и сделать весь раздел увеличен в анимированном виде).
Кроме того, я хотел бы, чтобы каждый раздел был модульным и не имел гигантского контроллера представления, который управляет всем. Я хотел бы, чтобы каждый раздел был по существу автономным. Я просто передаю данные в этот раздел, а затем он обрабатывает все, что связано с макетом и взаимодействием. Но опять же, реальная проблема заключается в том, чтобы эти представления могли изменять размер и иметь это обновление в родительском представлении (в настоящее время представление стека).
Но я действительно новичок в разработке iOS, и хотя я пытался учиться как можно быстрее, я все еще не уверен, что способ, которым я это делаю сейчас (представление прокрутки с представлением стека внутри него), является лучший подход или если есть лучшие подходы. Сначала я попробовал это в табличном представлении со статическими ячейками, где каждая строка была отдельным разделом. Но тогда заставить дочерние контроллеры представления изменять размер строки в родительском табличном представлении не получалось так хорошо. С тех пор я также отказался от того, чтобы каждый раздел был отдельным контроллером представления, и просто сделал каждый раздел представлением (а не контроллером представления), чтобы, надеюсь, упростить изменение размера, но я все еще сталкиваюсь с проблемами. Я также рассматривал представления коллекций, но мне также нужно иметь возможность поддерживать iOS 12 (или я могу отказаться от поддержки iOS 12, если мне действительно нужно, и просто поддерживать iOS 13+).
Но, повторюсь, моя общая цель состоит в том, чтобы иметь какой-то способ компоновки этого интерфейса, состоящего из разных представлений, каждое из которых обрабатывает разные данные. Я хотел бы, чтобы каждый вид мог изменять размер и чтобы он был гладким. И я хотел бы, чтобы каждый раздел интерфейса был модульным, чтобы избежать одного большого контроллера представления.
Обновление 2
Следуя предложению обернуть табличное представление в UIView, а затем установить два нижних ограничения с разными приоритетами, вот что я получаю. Я также получаю этот эффект каждый раз, когда пытаюсь анимировать такие вещи, как ограничение высоты представлений. Я думаю, это потому, что общее представление здесь содержится внутри представления стека, поэтому я думаю, что представление стека что-то делает, когда его организованное подпредставление меняет размер.
На картинке здесь показано как расширение табличного представления, так и его свертывание. В свернутом виде видны три строки, а в развернутом — пять.
Желтые и синие представления представляют другие представления на странице. Они не являются частью этого представления и не являются частью представления стека, в котором они содержатся. Это просто другие части страницы, включенные сюда, чтобы показать эту проблему. Все представления здесь содержатся в представлении стека, и я думаю, что это вызывает проблему с анимацией, но я не уверен, как это исправить.
reloadSections(_:with:)
, чтобы перезагрузить определенный раздел. - person pqteru   schedule 07.05.2021frame.height
перед добавлением каких-либо строк, а затем добавляет строки. Но это приводит к тому, что остальные разделы ниже этого раздела таблицы прыгают вниз, а не плавно анимируются. Я также попытался полностью заполнить таблицу, а затем добавить ограничение по высоте для таблицы, но это также вызвало прыжки из-за представления стека, в которое оно завернуто. Есть ли лучший способ размещения интерфейсов, чем использование представления стека? - person ashipma   schedule 07.05.2021Update - a high level overview of what I am trying to do
. Возможно, вы видели это в предыдущем вопросе, и он похож, но я немного обновил его с учетом моих общих целей. Но я не уверен, какой лучший подход к размещению этого контента, поэтому, если то, как я делаю это сейчас, неправильно, я могу изменить его. Но еще раз спасибо за все. Я очень ценю вашу помощь во всех моих вопросах. - person ashipma   schedule 07.05.2021