iOS - Tableviewcell(VFL代碼布局)與(Self Sizing Cells)配合使用

上一篇寫了cell的iOS8的新特性(Self Sizing Cells)可以自己適配cell高度,這里用AutoLayout的VFL純代碼添加布局約束來配合使用一下,以及我自己遇到的一些坑。。廢話不多說,先介紹一下什么是VFL。

VFL(Visual Format Language):可視化格式語言

VFL的語法介紹:
  • “H”:表示這是個水平方向上的約束;
    “V”:表示這是個垂直方向上的約束。
  • "|" :表示所設置視圖的父視圖superview。
  • "-" :表示間距。
  • "@":表示優先級
  • "[xxview]" :這個括號里面放置你要設置的視圖。

例: *V:|-8-[Textlabel(30)]-8-| *
在垂直方向上,Textlabel距父視圖頂部距離為8,距父視圖底部距離為8,高度為30。

添加約束的方法:

+(NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;

  • format: 是VFL字符串。
  • opts:設置VFL語句中的視圖相互間的對齊方式,一般默認傳0即可。
  • metrics:字典。一般是把VFL字符串中涉及到的高度、寬帶等數據參數轉為字典存到metrics中。在format中,高度、寬度等數據參數就用metrics中的key代替,然后編譯器解析時會自動替換metrics中的值 value。
  • views: 字典。把format中所有相關的視圖控件放入這個字典。

VFL與iOS8新特性(Self Sizing Cells)自適應高度配合

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.buttonArr = [NSArray arrayWithObjects:@"北京香格里拉飯店從去年開始就邀請入住酒店的愛心明星們在酒店的吉祥物小熊童童身上簽下他們的名字,加入愛心競拍的隊伍中,截止到現在我們一共籌得愛心款項人民幣 24776 元。其中最高的一只明星簽名小熊拍價高達10000元人民幣。 在北京香格里拉飯店27歲生日的今天,我們在媒體朋友們、啟喑實驗學校老師和學生及客人們的見證、祝福和陪伴中一起度過了一個意義非凡的生日,愛心傳遞和善款交付儀式圓滿成功!今天的儀式只是我們這個慈善項目的一個開始,會有越來越多的明星朋友加入到其中,也會有更多的簽名小熊參與競拍。這是一場愛的接力賽,希望您和您的朋友都能關注北京香格里拉飯店的官方微信和微博,來參與到我們的競拍活動中來。愛心“童童”的起拍價為人民幣1000元,想要為孩子們奉獻一份力量,同時收藏自己偶像簽名的愛心人士可致電(8610)6841 2211 轉 6901,發郵件至chris.ma@shangri-la.com,微博私信“北京香格里拉飯店”或微信留言等多種方式聯系酒店參與競拍。競拍金額最高的愛心人士不僅能夠得到中意的明星簽字“童童”,還將被邀請到之后的活動現場,親自見",
                      nil];
    self.MTableView.delegate = self;
    self.MTableView.dataSource = self;
    self.MTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    [self.MTableView registerNib:[UINib nibWithNibName:@"MTableViewCell" bundle:nil] forCellReuseIdentifier:@"MTableViewCell"];
    
    //高度自動適配(只適用于cell極少數量下使用)
    self.MTableView.estimatedRowHeight = 20;
    self.MTableView.rowHeight = UITableViewAutomaticDimension;
}

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

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    MTableViewCell  *(^block_textCell)()= ^MTableViewCell*() {
        MTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MTableViewCell" forIndexPath:indexPath];
        [cell cellLableGetText:self.buttonArr[indexPath.row]];
        [cell layoutIfNeeded];
        return cell;
    };
    return block_textCell();
}

cell.m

-(void)cellLableGetText:(NSString *)contentText{
    UILabel* Textlabel =[[UILabel alloc] init];
    Textlabel.text=contentText;
    Textlabel.numberOfLines=0;
    Textlabel.lineBreakMode = NSLineBreakByWordWrapping;
    Textlabel.translatesAutoresizingMaskIntoConstraints=NO; //使用VFL布局約束要加這一句,不然會報錯
    [self.contentView addSubview:Textlabel];
    //純代碼添加水平方向約束
    NSArray *constraints1=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[Textlabel]-|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:NSDictionaryOfVariableBindings(Textlabel)];
    //純代碼添加垂直方向約束
    NSArray *constraints2=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[Textlabel]-8-|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:NSDictionaryOfVariableBindings(Textlabel)];
    /*format: 是VFL字符串。
     opts:設置VFL語句中的視圖相互間的對齊方式,一般默認傳0即可。
     metrics:字典。一般是把VFL字符串中涉及到的高度、寬帶等數據參數轉為字典存到metrics中。在format中,高度、寬度等數據參數就用metrics中的key代替,然后編譯器解析時會自動替換metrics中的值 value。
     views:  字典。把format中所有相關的視圖控件放入這個字典。
     */
    [self.contentView addConstraints:constraints1];
    [self.contentView addConstraints:constraints2];

}

看看cell上方的是lable的控件,簡單約束好后效果實現如下,達到了我想要的效果:

22701610-94D3-4617-86A3-935BA6401516.png

但是。。有個坑就是當我不想使用lable的時候,換成了button:

-(void)cellButtonGetText:(NSString *)contentText{
    UIButton *Textbutton = [[UIButton alloc] init];
    Textbutton.backgroundColor = [UIColor clearColor];
    [Textbutton setTitle:contentText forState:UIControlStateNormal];
    [Textbutton setTitleColor:[UIColor brownColor] forState:UIControlStateNormal];
    Textbutton.titleLabel.font = [UIFont systemFontOfSize:15];
    Textbutton.titleLabel.numberOfLines = 0;
    Textbutton.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
    Textbutton.translatesAutoresizingMaskIntoConstraints = NO; //使用VFL布局約束要加這一句,不然會報錯
    [Textbutton sizeToFit];
    [Textbutton layoutIfNeeded];
    [self.contentView addSubview:Textbutton];


    //純代碼添加水平方向約束
    NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[Textbutton]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(Textbutton)];
    //純代碼添加垂直方向約束
    NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[Textbutton]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(Textbutton)];
    
    /*format: 是VFL字符串。
     opts:設置VFL語句中的視圖相互間的對齊方式,一般默認傳0即可。
     metrics:字典。一般是把VFL字符串中涉及到的高度、寬帶等數據參數轉為字典存到metrics中。在format中,高度、寬度等數據參數就用metrics中的key代替,然后編譯器解析時會自動替換metrics中的值 value。
     views:  字典。把format中所有相關的視圖控件放入這個字典。
     */
    [self.contentView addConstraints:constraintsH];
    [self.contentView addConstraints:constraintsV];
    [super layoutSubviews];
}

在運行之后發現:


2.png

咦。。這是什么情況,cell高度怎么木有適配起來,哪里寫錯了嗎?在我查看一番發現原來是因為button的文字是在它的titlelable上,titlelable高度是根據文字的高度適配了,但是button的高度沒有適配起來,而cell的新特性自動適配是根據button來適配的,所以會出現上面的效果,看看層級結構如下:

3.png

看到上面的層級關系,我們大概可以想到就是要把button和他的titlelable也要給約束起來,那么就要用到這個屬性:metrics。“[Textlabel(30)]”在這里高度30是一個固定值,但如果這個值是變動的呢?那么就需要metrics這個屬性傳入,更改方法如下:

-(void)cellButtonGetText:(NSString *)contentText{
    UIButton *Textbutton = [[UIButton alloc] init];
    Textbutton.backgroundColor = [UIColor clearColor];
    [Textbutton setTitle:contentText forState:UIControlStateNormal];
    [Textbutton setTitleColor:[UIColor brownColor] forState:UIControlStateNormal];
    Textbutton.titleLabel.font = [UIFont systemFontOfSize:15];
    Textbutton.titleLabel.numberOfLines = 0;
    Textbutton.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
    Textbutton.translatesAutoresizingMaskIntoConstraints = NO; //使用VFL布局約束要加這一句,不然會報錯
    [Textbutton sizeToFit];
    [Textbutton layoutIfNeeded];
    [self.contentView addSubview:Textbutton];

    
    CGSize expectedSize = [Textbutton.titleLabel sizeThatFits:CGSizeMake([UIScreen mainScreen].bounds.size.width, 0)];
    
    //算出文字適配寬度后的高度,傳入到約束里
    NSDictionary *metrics = @{@"lableHeight": @(expectedSize.height)};
    
    //純代碼添加水平方向約束
    NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[Textbutton]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(Textbutton)];
    //純代碼添加垂直方向約束
    NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[Textbutton(lableHeight)]-8-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(Textbutton)];
    
    /*format: 是VFL字符串。
     opts:設置VFL語句中的視圖相互間的對齊方式,一般默認傳0即可。
     metrics:字典。一般是把VFL字符串中涉及到的高度、寬帶等數據參數轉為字典存到metrics中。在format中,高度、寬度等數據參數就用metrics中的key代替,然后編譯器解析時會自動替換metrics中的值 value。
     views:  字典。把format中所有相關的視圖控件放入這個字典。
     */
    [self.contentView addConstraints:constraintsH];
    [self.contentView addConstraints:constraintsV];
    [super layoutSubviews];
}

這回再運行起來,就可以了。

小小的demo傳送門

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容