问题描述
我正在开发应用中的一项功能,用户可以在其中点击有关汽车的某些属性(例如其颜色),然后会显示不同颜色的列表。
这只是页面的一部分。整个页面由不同的视图和视图控制器组成,所有视图和视图控制器都包裹在一个垂直堆栈视图中,但我认为这不是导致动画问题的原因。这是页面的整体结构:
-
UIScrollView
-
UIStackView
UIViewController
UIView
-
UITableViewController
- ...
-
但是对于这个问题,我只是展示了这个表格所在的页面部分。
所以我在表格的动画方面遇到了问题,稍后可以在 gif 中看到。该部分的结构方式是它是一个 UITableViewController 子类,它接收模型(标题和汽车颜色列表),并为每个模型元素显示不同的表格部分。
每个部分都有一个部分标题,这是用户点击的部分。它显示颜色并显示预览图像。当它被点击时,一个表格行被添加到该部分的表格中,并且该更改是动画的。添加到表格中的表格视图行包含一个 UICollectionView,用于水平布置内容。这个想法来自WWDC 2010 - Mastering Table Views视频。
基本上是这样的。每个部分标题都是交互式部分,您可以点击它。然后该部分中显示的行有一个集合视图。
* SectionHeader
* SectionHeader
* Table row containing a UICollectionView
* SectionHeader
我遇到的问题是动画的行为方式很奇怪,如下图所示。
第一张图片显示了如果展开一行下面有其他行会发生什么。在这种情况下,表格中的其他两行似乎基本上浮动在动画中的新行的内容之上。此外,在该部分的底部,这两行从底部进入,就像前一行一样两行被垂直压扁,直到消失。
此处的第二个动画显示了底部行的展开。这个更接近我想要的,除了行内容仍然短暂显示在分隔线上方的行顶部(这是上一节的节脚)。
这是我的表视图控制器类的代码。
MyAttributeTableViewController.h
#import <UIKit/UIKit.h>
#import "MyAttribute.h"
#import "MyAttributeTableViewCell.h"
NS_ASSUME_NONNULL_BEGIN
@interface MyAttributeTableViewController : UITableViewController<MyAttributeDelegate>
//this represents each section of the table. It contains a title (color,for example),a selected value (red),//and a list of possible values that will be used to display the collection view when the section is expanded.
@property (strong,nonatomic) NSArray<MyAttribute *> *modelattributes;
@end
NS_ASSUME_NONNULL_END
MyAttributeTableViewController.m
#import "MyAttributeTableViewController.h"
#import "MyAttributeTableHeaderView.h"
#import "MyAttributeTableViewCell.h"
@interface MyAttributeTableViewController ()
//this keeps track of which sections are expanded. Initially,all sections start out
//not expanded. Then,upon tap,a section's expanded status is toggled here. This is
//used by the table view's data source to kNow when to display a row in a section.
@property (strong,nonatomic) NSMutableArray<NSNumber *> *itemsExpanded;
@end
@implementation MyAttributeTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionFooterHeight = CGFLOAT_MIN;
//this xib file only contains the UICollectionView that is shown upon expanding the section.
//There is nothing that interesting in this file,but I have some screenshots of the
//attribute inspector for this xib file after this code.
[self.tableView registerNib:[UINib nibWithNibName:@"MyAttributeTableViewCell" bundle:nil] forCellReuseIdentifier:@"MyAttributeTableViewCell"];
[self.tableView registerClass:[MyAttributeTableHeaderView class] forheaderfooterViewReuseIdentifier:@"AttributeHeaderView"];
[self.tableView invalidateIntrinsicContentSize];
}
- (void)setAttributeOptions:(NSArray<MyAttribute *> *)modelattributes {
self->_modelattributes = modelattributes;
self->_itemsExpanded = [NSMutableArray arrayWithCapacity:[self->_modelattributes count]];
for (NSUInteger x=0; x<[self->_modelattributes count]; x++) {
[self->_itemsExpanded addobject:@NO];
}
[self.tableView reloadData];
}
//Todo: is this necessary?
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.preferredContentSize = self.tableView.contentSize;
}
#pragma mark - MyAttributeDelegate
- (void)twister:(MyAttributeTableViewCell *)cell didSelectItemAtIndex:(NSInteger)index {
UITableViewheaderfooterView *headerView = [self.tableView headerViewForSection:cell.sectionIndex];
if ([headerView isKindOfClass:[MyAttributeTableHeaderView class]]) {
MyAttributeTableHeaderView *twisterHeaderView = (MyAttributeTableHeaderView *)headerView;
twisterHeaderView.twister.selectedSwatchIndex = [NSNumber numberWithInteger:index];
[twisterHeaderView updateAttributeIfNeeded];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.modelattributes.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.itemsExpanded[section].boolValue ? 1 : 0;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
MyAttributeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyAttributeTableViewCell" forIndexPath:indexPath];
MyAttribute *twister = self.modelattributes[indexPath.section];
cell.swatches = twister.swatches;
NSNumber *swatchCellHeight = cell.swatchCellHeight;
if (swatchCellHeight) {
return swatchCellHeight.floatValue + 20.0f; //Todo: need to get this from the collection view
}
return 352.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if (section == self.modelattributes.count) {
return CGFLOAT_MIN;
}
return 1.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyAttributeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyAttributeTableViewCell" forIndexPath:indexPath];
MyAttribute *twister = self.modelattributes[indexPath.section];
cell.swatches = twister.swatches;
cell.sectionIndex = indexPath.section;
cell.delegate = self;
if ([twister isSwatchSelected]) {
NSInteger selectedindex = twister.selectedSwatchIndex.integerValue;
[cell.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedindex inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
}
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
MyAttributeTableHeaderView *cell = (MyAttributeTableHeaderView *)[tableView dequeueReusableheaderfooterViewWithIdentifier:@"AttributeHeaderView"];
if (cell.gestureRecognizers.count == 0) {
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleSection:)];
[cell addGestureRecognizer:tapRecognizer];
}
cell.sectionIndex = section;
cell.expanded = self.itemsExpanded[section].boolValue;
cell.twister = self.modelattributes[section];
return cell;
}
- (void)toggleSection:(UITapGestureRecognizer *)gesture {
MyAttributeTableHeaderView *destinationView = ((MyAttributeTableHeaderView *)gesture.view);
BOOL expanded = [destinationView toggleExpanded];
self.itemsExpanded[destinationView.sectionIndex] = [NSNumber numberWithBool:expanded];
UIView *viewToLayout = self.tableView;
while ([viewToLayout superview]) {
viewToLayout = viewToLayout.superview;
}
if (expanded) {
[UIView beginAnimations:@"expandTableAnimationId" context:nil];
[UIView setAnimationDuration:1.0f];
[CATransaction begin];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:destinationView.sectionIndex]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
[viewToLayout layoutIfNeeded];
[CATransaction commit];
[UIView commitAnimations];
} else {
[UIView beginAnimations:@"collapseTableAnimationId" context:nil];
[UIView setAnimationDuration:1.0f];
[CATransaction begin];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:destinationView.sectionIndex]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
[viewToLayout layoutIfNeeded];
[CATransaction commit];
[UIView commitAnimations];
}
}
@end
MyAttributeTableViewCell
有谁知道我做错了什么,或者如何让这些动画看起来正确(没有加倍的行,也没有在行上方显示动画时的集合视图)?或者,如果您知道一种更好的方法来处理这个可能不那么复杂的问题,我也对此持开放态度。我只是想有一个可扩展部分的列表,其中每个部分都有一个可选项目的集合视图。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)