zoukankan      html  css  js  c++  java
  • Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》

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

    在Github上的实例代码是DynamicTableViewCellHeight

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

    preferredMaxLayoutWidth

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

    User Interface

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

    这里,“引言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。

  • 相关阅读:
    eclipse 添加.gitignore
    HTTP method POST is not supported by this URL
    Nodejs 如何解决每次向后台发起请求时判断用户是否处于登录状态?
    Servlet 全局验证是否登录
    会员管理系统的设计和开发(1)
    C程序模拟实现银行家算法
    XPath Helper:chrome爬虫网页解析工具 Chrome插件
    scrapy爬虫出现Forbidden by robots.txt
    廖雪峰
    Nodejs中export的作用
  • 原文地址:https://www.cnblogs.com/gatsbywang/p/4216706.html
Copyright © 2011-2022 走看看