Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》

这篇博客主要在于,解释如何通过仅仅使用Autolayout很很少的代码,显示高度不同的Cell。虽然标题说的是TableView,但是CollectionView同样适合。但是,这种方法只使用iOS7和iOS8。

在Github上的实例代码是DynamicTableViewCellHeight

这个Demo显示了一些名人名言,他看起来像这样:

Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》

preferredMaxLayoutWidth

这种方法,主要来自于preferredMaxLayoutWidth属性。对于更多高级用法,请看Auto Layout and Views that Wrap

User Interface

我使用的是Storyboard, 但是你能够使用xib或者代码, 对于如何使用代码,你可以看一下这篇文章AutoSize UITableViewCell height programmatically

Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》

Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》

这里,“引言Label”显示多行(通过设置numberOfLines属性为0)。因为我们有2个Label,AutoLayout不知道如何扩大,不知道cell的大小改变时哪一个Label保持大小不变。在这种情况下,我想要“引言Label”扩大,所以减少减少垂直方向Hugging优先级,并且增加保持自身大小不变优先级。

关于hugging和resistance优先级的区别,可以看这篇文章Cocoa Autolayout: content hugging vs content compression resistance priority

注意:

1、Dynamic Table View Cell Height and Auto Layout,这篇博客告诉我们,我们应该给labels的“intrinsic content”属性到1000,并且设置Intrinsic Size为占位符大小。我认为这是不需要的。

2、你必须给TableViewCell的contentView设置属性。

3、对于在Interface Builder中的CollectionViewCell。你不会看到contentView,但是你真的是和contentView打交道。

Cell

QuoteTableViewCell.h

1 @interface QuoteTableViewCell : UITableViewCell

2 @property (weak, nonatomic) IBOutlet UILabel *numberLabel;

3 @property (weak, nonatomic) IBOutlet UILabel *quoteLabel;

4  

5 @end

QuoteTableViewCell.m

 1 @implementation QuoteTableViewCell

 2  

 3 // (1)

 4 - (void)setBounds:(CGRect)bounds

 5 {

 6     [super setBounds:bounds];

 7  

 8     self.contentView.frame = self.bounds;

 9 }

10  

11 - (void)layoutSubviews

12 {

13     [super layoutSubviews];

14  

15     // (2)

16     [self.contentView updateConstraintsIfNeeded];

17     [self.contentView layoutIfNeeded];

18  

19     // (3)

20     self.quoteLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.quoteLabel.frame);

21 }

22  

23 @end

ViewController

ViewController.m

  1 #define SYSTEM_VERSION                              ([[UIDevice currentDevice] systemVersion])

  2 #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([SYSTEM_VERSION compare:v options:NSNumericSearch] != NSOrderedAscending)

  3 #define IS_IOS8_OR_ABOVE                            (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0"))

  4  

  5 @interface ViewController () <UITableViewDataSource, UITableViewDelegate>

  6  

  7 @property (weak, nonatomic) IBOutlet UITableView *tableView;

  8 @property (nonatomic, strong) NSArray *items;

  9 @property (nonatomic, strong) QuoteTableViewCell *prototypeCell;

 10  

 11 @end

 12  

 13 @implementation ViewController

 14  

 15 - (void)viewDidLoad {

 16     [super viewDidLoad];

 17  

 18     [self setupTableView];

 19     [self loadData];

 20 }

 21  

 22 - (void)didReceiveMemoryWarning {

 23     [super didReceiveMemoryWarning];

 24     // Dispose of any resources that can be recreated.

 25 }

 26  

 27 #pragma mark - Setup

 28 - (void)setupTableView

 29 {

 30     self.tableView.dataSource = self;

 31     self.tableView.delegate = self;

 32 }

 33  

 34 #pragma mark - Data

 35 - (void)loadData

 36 {

 37     NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"];

 38     self.items = [[NSArray alloc] initWithContentsOfFile:plistPath];

 39  

 40     [self.tableView reloadData];

 41 }

 42  

 43 #pragma mark - PrototypeCell

 44 // (4)

 45 - (QuoteTableViewCell *)prototypeCell

 46 {

 47     if (!_prototypeCell) {

 48         _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];

 49     }

 50  

 51     return _prototypeCell;

 52 }

 53  

 54 #pragma mark - Configure

 55 - (void)configureCell:(QuoteTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

 56 {

 57     NSString *quote = self.items[indexPath.row];

 58  

 59     cell.numberLabel.text = [NSString stringWithFormat:@"Quote %ld", (long)indexPath.row];

 60     cell.quoteLabel.text = quote;

 61 }

 62  

 63 #pragma mark - UITableViewDataSouce

 64 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

 65 {

 66     return 1;

 67 }

 68  

 69 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

 70 {

 71     return self.items.count;

 72 }

 73  

 74 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

 75 {

 76     QuoteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];

 77  

 78     [self configureCell:cell forRowAtIndexPath:indexPath];

 79  

 80     return cell;

 81 }

 82  

 83 #pragma mark - UITableViewDelegate

 84 // (5)

 85 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

 86 {

 87     return UITableViewAutomaticDimension;

 88 }

 89  

 90 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

 91 {

 92     // (6)

 93     if (IS_IOS8_OR_ABOVE) {

 94         return UITableViewAutomaticDimension;

 95     }

 96  

 97     // (7)

 98     //self.prototypeCell.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds));

 99  

100     [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath];

101  

102     // (8)

103     [self.prototypeCell updateConstraintsIfNeeded];

104     [self.prototypeCell layoutIfNeeded];

105  

106     // (9)

107     return [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

108  

109 }

110  

111 @end

注意以下几点:

1、Auto Layout in UICollectionViewCell not working

2、AutoSize UITableViewCell height programmatically

Make sure the contentView does a layout pass here so that its subviews have their frames set, which we need to use to set the preferredMaxLayoutWidth below.



Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label’s frame, as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height.

3、你只需要调用[self.contentView layoutIfNeeded]。

4、如果你要改变某些限制,你需要调用[self.contentView updateConstraintsIfNeeded]。

5、如果你调用[self.contentView updateConstraintsIfNeeded],你必须在之前调用[self.contentView layoutIfNeeded]。

6、不需要调用[self.contentView setsNeedLayout],或者self.contentView setsNeedUpdateConstraints]。

ViewController

  1 #define SYSTEM_VERSION                              ([[UIDevice currentDevice] systemVersion])

  2 #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([SYSTEM_VERSION compare:v options:NSNumericSearch] != NSOrderedAscending)

  3 #define IS_IOS8_OR_ABOVE                            (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0"))

  4  

  5 @interface ViewController () <UITableViewDataSource, UITableViewDelegate>

  6  

  7 @property (weak, nonatomic) IBOutlet UITableView *tableView;

  8 @property (nonatomic, strong) NSArray *items;

  9 @property (nonatomic, strong) QuoteTableViewCell *prototypeCell;

 10  

 11 @end

 12  

 13 @implementation ViewController

 14  

 15 - (void)viewDidLoad {

 16     [super viewDidLoad];

 17  

 18     [self setupTableView];

 19     [self loadData];

 20 }

 21  

 22 - (void)didReceiveMemoryWarning {

 23     [super didReceiveMemoryWarning];

 24     // Dispose of any resources that can be recreated.

 25 }

 26  

 27 #pragma mark - Setup

 28 - (void)setupTableView

 29 {

 30     self.tableView.dataSource = self;

 31     self.tableView.delegate = self;

 32 }

 33  

 34 #pragma mark - Data

 35 - (void)loadData

 36 {

 37     NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"];

 38     self.items = [[NSArray alloc] initWithContentsOfFile:plistPath];

 39  

 40     [self.tableView reloadData];

 41 }

 42  

 43 #pragma mark - PrototypeCell

 44 // (4)

 45 - (QuoteTableViewCell *)prototypeCell

 46 {

 47     if (!_prototypeCell) {

 48         _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];

 49     }

 50  

 51     return _prototypeCell;

 52 }

 53  

 54 #pragma mark - Configure

 55 - (void)configureCell:(QuoteTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

 56 {

 57     NSString *quote = self.items[indexPath.row];

 58  

 59     cell.numberLabel.text = [NSString stringWithFormat:@"Quote %ld", (long)indexPath.row];

 60     cell.quoteLabel.text = quote;

 61 }

 62  

 63 #pragma mark - UITableViewDataSouce

 64 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

 65 {

 66     return 1;

 67 }

 68  

 69 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

 70 {

 71     return self.items.count;

 72 }

 73  

 74 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

 75 {

 76     QuoteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([QuoteTableViewCell class])];

 77  

 78     [self configureCell:cell forRowAtIndexPath:indexPath];

 79  

 80     return cell;

 81 }

 82  

 83 #pragma mark - UITableViewDelegate

 84 // (5)

 85 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

 86 {

 87     return UITableViewAutomaticDimension;

 88 }

 89  

 90 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

 91 {

 92     // (6)

 93     if (IS_IOS8_OR_ABOVE) {

 94         return UITableViewAutomaticDimension;

 95     }

 96  

 97     // (7)

 98     //self.prototypeCell.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds));

 99  

100     [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath];

101  

102     // (8)

103     [self.prototypeCell updateConstraintsIfNeeded];

104     [self.prototypeCell layoutIfNeeded];

105  

106     // (9)

107     return [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

108  

109 }

110  

111 @end

7、原型cell绝不会显示出来,它用来布局一个cell并且决定一个需要的高度。

8、你能够使用UITableViewAutomaticDimension,或者使用一个大约合理的高度。

9、iOS8 autoSizing属性需要使用UITableViewAutomaticDimension。

 

你可能感兴趣的:(UITableViewCell)