亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

iOS App開發(fā)中使cell高度自適應(yīng)的黑魔法詳解

 更新時(shí)間:2016年03月20日 21:13:22   作者:Vito Zhang  
這篇文章主要介紹了iOS App開發(fā)中使cell高度自適應(yīng)的黑魔法詳解,作者利用iOS8以后的新特性講解了TableView、CollectionView中的cell高度自適應(yīng)以及UITextView輸入內(nèi)容實(shí)時(shí)更新cell高度的方法,需要的朋友可以參考下

在使用 table view 的時(shí)侯經(jīng)常會遇到這樣的需求:table view 的 cell 中的內(nèi)容是動態(tài)的,導(dǎo)致在開發(fā)的時(shí)候不知道一個(gè) cell 的高度具體是多少,所以需要提供一個(gè)計(jì)算 cell 高度的算法,在每次加載到這個(gè) cell 的時(shí)候計(jì)算出 cell 真正的高度。

在 iOS 8 之前

沒有使用 Autolayout 的情況下,需要實(shí)現(xiàn) table view delegate 的 tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 方法,在這個(gè)方法中計(jì)算并返回 cell 的高度。比如,我有一個(gè)可以顯示任意行數(shù)的純文本 cell,計(jì)算 cell 的代碼可以是這樣:

復(fù)制代碼 代碼如下:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let content = self.datas[indexPath.row] as String

    let padding: CGFloat = 20
    let width = tableView.frame.size.width - padding * 2;

    let size = CGSizeMake(width, CGFloat.max)
    let attributes = [NSFontAttributeName: UIFont(name: "Helvetica", size: 14)!]
    let frame = content.boundingRectWithSize(size,
        options: NSStringDrawingOptions.UsesLineFragmentOrigin,
        attributes: attributes,
        context: nil)
    return frame.size.height+1;
}


上面的代碼是一個(gè)最簡單的例子,這個(gè)例子看起來好像沒有什么問題。但是通過查看這個(gè) delegate 方法的文檔后,可以知道,在每次 reload tableview 的時(shí)候,程序會先計(jì)算出每一個(gè) cell 的高度,等所有高度計(jì)算完畢,確定了 tableview 的總的高度后,才開始渲染視圖并顯示在屏幕上。這意味著在顯示 table view 之前需要執(zhí)行一堆的計(jì)算,并且這是在主線程中進(jìn)行的,如果計(jì)算量太大程序就很有可能出現(xiàn)卡頓感。比如: table view 的數(shù)據(jù)有上千條,或者計(jì)算高度的代碼中還要先獲取圖片再根據(jù)圖片計(jì)算高度,這些操作都是非常慢的。

如果在 cell 中使用了 autolayout,在計(jì)算 cell 高度時(shí)會更麻煩。有興趣的可以看這里有篇關(guān)于如何在 autolayout 下動態(tài)計(jì)算高度 的文章。

為什么不能等滾動到某個(gè) cell 的時(shí)候,再調(diào)用計(jì)算這個(gè) cell 高度的 delegate 呢?原因是 tableview 需要獲得它的內(nèi)容的總高度,用這個(gè)高度去確定滾動條的大小等。直到 iOS 7 UITableViewDelegate中添加了新的 API

tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
這個(gè)方法用于返回一個(gè) cell 的預(yù)估高度,如果在程序中實(shí)現(xiàn)了這個(gè)方法,tableview 首次加載的時(shí)候就不會調(diào)用heightForRowAtIndexPath 方法,而是用 estimatedHeightForRowAtIndexPath 返回的預(yù)估高度計(jì)算 tableview 的總高度,然后 tableview 就可以顯示出來了,等到 cell 可見的時(shí)候,再去調(diào)用heightForRowAtIndexPath 獲取 cell 的正確高度。

通過使用estimatedHeightForRowAtIndexPath 這個(gè) Delegate 方法,解決了首次加載 table view 出現(xiàn)的性能問題。但還有一個(gè)麻煩的問題,就是在 cell 沒有被加載的時(shí)候計(jì)算 cell 的高度,上面給出的代碼中,僅僅是計(jì)算一個(gè) NSString 的高度,就需要不少代碼了。這種計(jì)算實(shí)際上是必須的,然而在 iOS 8 開始,你可能可以不用再寫這些煩人的計(jì)算代碼了!

iOS 8 的魔法

在 iOS 8 中,self size cell 提供了這樣一種機(jī)制:cell 如果有一個(gè)確定的寬度/高度,autolayout 會自動根據(jù) cell 中的內(nèi)容計(jì)算出對應(yīng)的高度/寬度。

TableView 中的 cell 自適應(yīng)

要讓 table view 的 cell 自適應(yīng)內(nèi)容,有幾個(gè)要點(diǎn):

設(shè)置的 AutoLayout 約束必須讓 cell 的 contentView 知道如何自動延展。關(guān)鍵點(diǎn)是 contentView 的 4 個(gè)邊都要設(shè)置連接到內(nèi)容的約束,并且內(nèi)容是會動態(tài)改變尺寸的。
UITableView 的 rowHeight 的值要設(shè)置為 UITableViewAutomaticDimension
和 iOS 7 一樣,可以實(shí)現(xiàn) estimatedHeightForRowAtIndexPath 方法提升 table view 的第一次加載速度。
任何時(shí)候 cell 的 intrinsicContentSize 改變了(比如 table view 的寬度變了),都必須重新加載 table view 以更新 cell。
例子

在 Xcode 中新建一個(gè)項(xiàng)目,在 storyboard 中創(chuàng)建一個(gè) UITableViewController 的 IB,創(chuàng)建一個(gè)如下樣子的 cell:

這個(gè) cell 中有 3 個(gè)元素,其中 imageView 的 autoLayout 約束為:

  • imageView 左邊離 contentView 左邊 0
  • imageView 上邊離 contentView 上邊 0
  • imageView 的 width 和 height 為 80
  • imageView 下邊離 contentView 下邊大于等于 0(為了防止內(nèi)容太少,導(dǎo)致 cell 高度小于圖片高度)

titleLabel 的 autoLayout 約束為:

  • titleLabel 左邊離 imageView 右邊 8
  • titleLabel 上邊和 imageView 上邊在同一只線上
  • titleLabel 右邊離 contentView 右邊 0
  • titleLabel 下邊離 description 上邊 8
  • titleLabel 的高度小于等于 22,優(yōu)先級為 250

descriptionLabel 的約束為:

  • descriptionLabel 左邊和 titleLabel 左邊在同一直線上
  • descriptionLabel 上邊里 titleLabel 8
  • descriptionLabel 下邊里 contentView 下邊 0
  • descriptionLabel 右邊離 contentView 右邊 0

然后在這個(gè) IB 對應(yīng)的 UITableViewController 中加載一些數(shù)據(jù)進(jìn)去,顯示效果如圖:

實(shí)現(xiàn)這個(gè)效果,我除了設(shè)置了 autoLayout,還設(shè)置了 tableView 的 rowHeight = UITableViewAutomaticDimension,然后就是這樣了。一點(diǎn)計(jì)算 cell 高度的代碼都沒有!!我連 heightForRowAtIndexPath都不用實(shí)現(xiàn),真的是….爽出味??!所以如果已經(jīng)在開發(fā) iOS 8 Only 的應(yīng)用了一定要用autolayout,把煩人的計(jì)算交給 autolayout 去吧。

CollectionView 中的 cell 自適應(yīng)

在 collection view 中也能讓 cell 自適應(yīng)內(nèi)容大小,如果 UICollectionView 的 layout 是一個(gè) UICollectionViewFlowLayout,只需要將 layout.itemSize = ... 改成 layout.estimatedItemSize = ...。 只要設(shè)置了 layout 的 estimatedItemSize,collection view 就會根據(jù) cell 里面的 autolayout 約束去確定cell 的大小。

原理:

  • collection view 根據(jù) layout 的 estimatedItemSize 算出估計(jì)的 contentSize,有了 contentSize collection view 就開始顯示
  • collection view 在顯示的過程中,即將被顯示的 cell 根據(jù) autolayout 的約束算出自適應(yīng)內(nèi)容的 size
  • layout 從 collection view 里獲取更新過的 size attribute
  • layout 返回最終的 size attribute 給 collection view
  • collection 使用這個(gè)最終的 size attribute 展示 cell

UITextView 輸入內(nèi)容實(shí)時(shí)更新 cell 的高度
在一個(gè)動態(tài)數(shù)據(jù)的 table view 中,cell 根據(jù) text view 內(nèi)容的輸入實(shí)時(shí)改變 cell 和 table view 的高度。自動計(jì)算 cell 高度的功能使用 iOS 8 才支持的自適應(yīng) cell,先上圖,我們最終要實(shí)現(xiàn)的效果是這樣的:

實(shí)現(xiàn)上面效果的基本原理是:

  • 在 cell 中設(shè)置好 text view 的 autolayout,讓 cell 可以根據(jù)內(nèi)容自適應(yīng)大小
  • text view 中輸入內(nèi)容,根據(jù)內(nèi)容更新 textView 的高度
  • 調(diào)用 tableView 的 beginUpdates 和 endUpdates,重新計(jì)算 cell 的高度

將 text view 更新后的數(shù)據(jù)保存,以免 table view 滾動超過一屏再滾回來 text view 中的數(shù)據(jù)又不刷新成原來的數(shù)據(jù)了。

功能具體實(shí)現(xiàn)方法:

新建一個(gè)項(xiàng)目,拉出 TableViewController,在 cell 上添加一個(gè) UITextView。

首先設(shè)置 text view 的 autolayout,比較關(guān)鍵的 constraint 是要設(shè)置 textView 的高度大于等于一個(gè)值。如圖:

然后,設(shè)置 UITextView 的 scrollEnable 為 NO。這一點(diǎn)很關(guān)鍵,如果不設(shè)置為 NO,UITextView 在內(nèi)容超出 frame 后,重新設(shè)置 text view 的高度會失效,并出現(xiàn)滾動條。

根據(jù)剛才在 storyboard 中創(chuàng)建的 cell,新建一個(gè) UITableViewCell 類。

復(fù)制代碼 代碼如下:

#import <UIKit/UIKit.h>

@interface TextViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UITextView *textView;

@end


創(chuàng)建 TableViewController 并初始化一些數(shù)據(jù)
復(fù)制代碼 代碼如下:

#import "TableViewController.h"
#import "TextViewCell.h"

@interface TableViewController ()

@property (nonatomic, strong) NSArray *data;

@end


復(fù)制代碼 代碼如下:

@implementation TableViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  //  支持自適應(yīng) cell
  self.tableView.estimatedRowHeight = 100;
  self.tableView.rowHeight = UITableViewAutomaticDimension;

  self.data = @[@"Cell 1 ", @"Cell 2", @"Cell 3", @"Cell 4", @"Cell 5", @"Cell 6", @"Cell 7", @"Cell 8"];
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  return [self.data count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  TextViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TextViewCell" forIndexPath:indexPath];
  cell.textView.text = self.data[indexPath.row];
  return cell;
}


使用上面的代碼項(xiàng)目已經(jīng)可以運(yùn)行了,但是 text view 還不能自動更新大小,下面來實(shí)現(xiàn) text view 根據(jù)內(nèi)容計(jì)算高度

先在 storyboard 中,將 UITextView 的 delegate 設(shè)置為 cell

在 TextViewCell.m 中實(shí)現(xiàn) - (void)textViewDidChange:(UITextView *)textView,每次 text view 內(nèi)容改變的時(shí)候,就重新計(jì)算一次 text view 的大小,并讓 table view 更新高度。

復(fù)制代碼 代碼如下:

#import "TextViewCell.h"

@implementation TextViewCell

- (void)textViewDidChange:(UITextView *)textView
{
  CGRect bounds = textView.bounds;

  // 計(jì)算 text view 的高度
  CGSize maxSize = CGSizeMake(bounds.size.width, CGFLOAT_MAX);
  CGSize newSize = [textView sizeThatFits:maxSize];
  bounds.size = newSize;

  textView.bounds = bounds;

  // 讓 table view 重新計(jì)算高度
  UITableView *tableView = [self tableView];
  [tableView beginUpdates];
  [tableView endUpdates];
}

- (UITableView *)tableView
{
  UIView *tableView = self.superview;

  while (![tableView isKindOfClass:[UITableView class]] && tableView) {
    tableView = tableView.superview;
  }

  return (UITableView *)tableView;
}

@end


這樣就已經(jīng)實(shí)現(xiàn)了 text view 改變內(nèi)容自動更新 cell 高度的功能,這篇文章沒有涉及到計(jì)算 cell 高度的代碼,因?yàn)橛?jì)算 cell 高度的工作全部交給 iOS 8 的 autolayout 自動計(jì)算了,這讓我們少寫了許多令人痛苦的代碼。

最后:為了防止 table view 過長,導(dǎo)致滾動后重新加載 cell,會讓 text view 中的內(nèi)容還原的問題,我們應(yīng)該在更新了 text view 的內(nèi)容之后保存數(shù)據(jù)。(如果是在編輯狀態(tài)下,還需要考慮取消編輯后的回滾功能。 普通數(shù)組數(shù)據(jù),可以保存一個(gè)原始數(shù)據(jù)的副本,如果用戶取消編輯,就設(shè)置 data 為原始數(shù)據(jù)的副本。如果是 NSManagedObject 對象可以使用 NSUndoManage,不過這些已經(jīng)超出本篇文章的內(nèi)容范圍了。)

為了在 text view 更新后能讓 TableViewController 中的 data 更新,需要為 cell 添加一個(gè) delegate,在 text view 更新后調(diào)用 delegate,TableViewController 中收到 delegate 信息后更新 data。

修改后的 TextViewCell.h

復(fù)制代碼 代碼如下:

#import <UIKit/UIKit.h>

@protocol TextViewCellDelegate;

@interface TextViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UITextView *textView;

@property (weak, nonatomic) id<TextViewCellDelegate> delegate;

@end


復(fù)制代碼 代碼如下:

@protocol TextViewCellDelegate <NSObject>

- (void)textViewCell:(TextViewCell *)cell didChangeText:(NSString *)text;

@end


在 TextView.m的 - (void)textViewDidChange:(UITextView *)textView 中添加 delegate 的調(diào)用
復(fù)制代碼 代碼如下:

- (void)textViewDidChange:(UITextView *)textView
{
  if ([self.delegate respondsToSelector:@selector(textViewCell:didChangeText:)]) {
    [self.delegate textViewCell:self didChangeText:textView.text];
  }

  // 計(jì)算 text view 的高度
  ...
  // 讓 table view 重新計(jì)算高度
  ...
}


最后在 TableViewController.m 的最后實(shí)現(xiàn) TextViewCellDelegate 的方法,更新 data
復(fù)制代碼 代碼如下:

#pragma mark - TextViewCellDelegate

- (void)textViewCell:(TextViewCell *)cell didChangeText:(NSString *)text
{
  NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

  NSMutableArray *data = [self.data mutableCopy];
  data[indexPath.row] = text;
  self.data = [data copy];
}

相關(guān)文章

  • IOS 城市定位詳解及簡單實(shí)例

    IOS 城市定位詳解及簡單實(shí)例

    這篇文章主要介紹了IOS 城市定位詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • iOS屏幕根據(jù)鍵盤自動變化高度

    iOS屏幕根據(jù)鍵盤自動變化高度

    這篇文章主要為大家詳細(xì)介紹了iOS屏幕根據(jù)鍵盤自動變化高度,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • iOS 三級下拉菜單功能實(shí)現(xiàn)

    iOS 三級下拉菜單功能實(shí)現(xiàn)

    多級下拉菜單在很多APP中都能應(yīng)用到,這篇文章主要介紹了iOS 多級下拉菜單功能實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解下。
    2017-03-03
  • 關(guān)于iOS GangSDK的使用 為App快速集成社群公會模塊

    關(guān)于iOS GangSDK的使用 為App快速集成社群公會模塊

    這篇文章主要介紹了iOS GangSDK的使用為App快速集成社群公會模塊功能的實(shí)現(xiàn)過程。
    2017-11-11
  • iOS中控制NSLog輸出時(shí)機(jī)詳解

    iOS中控制NSLog輸出時(shí)機(jī)詳解

    本文給大家介紹的是iOS開發(fā)中關(guān)于nslog的輸出時(shí)機(jī)的相關(guān)內(nèi)容,非常簡單實(shí)用,有需要的小伙伴可以參考下
    2017-12-12
  • 詳解IOS開發(fā)之實(shí)現(xiàn)App消息推送(最新)

    詳解IOS開發(fā)之實(shí)現(xiàn)App消息推送(最新)

    這篇文章主要介紹了詳解IOS開發(fā)之實(shí)現(xiàn)App消息推送(最新),具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • 更新了Xcode8 及 iOS10遇到的問題小結(jié)

    更新了Xcode8 及 iOS10遇到的問題小結(jié)

    更新了Xcode8 以及 iOS10,App訪問用戶的相機(jī)、相冊、麥克風(fēng)、通訊錄的權(quán)限都需要重新進(jìn)行相關(guān)的配置,不然在Xcode8中打開編譯的話會直接crash.這篇文章主要介紹了更新了Xcode8 及 iOS10遇到的問題小結(jié)的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • 移動端頁面在ios中不顯示圖片的解決方法

    移動端頁面在ios中不顯示圖片的解決方法

    下面小編就為大家?guī)硪黄苿佣隧撁嬖趇os中不顯示圖片的解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • iOS微信第三方登錄實(shí)例

    iOS微信第三方登錄實(shí)例

    這篇文章主要為大家詳細(xì)介紹了iOS微信第三方登錄實(shí)現(xiàn)過程,一步一步告訴大家iOS微信實(shí)現(xiàn)第三方登錄的方法,感興趣的小伙伴們可以參考一下
    2016-12-12
  • iOS開發(fā)實(shí)戰(zhàn)之Label全方位對齊的輕松實(shí)現(xiàn)

    iOS開發(fā)實(shí)戰(zhàn)之Label全方位對齊的輕松實(shí)現(xiàn)

    這篇文章主要給大家介紹了關(guān)于iOS開發(fā)實(shí)戰(zhàn)之輕松實(shí)現(xiàn)Label全方位對齊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10

最新評論