根据文字动态调整 UILabel 高度

写了一个自定义的弹出框,其中用到了根据 UILabel 文字的多少自动计算 label 的高度,编写的过程中还是会遇到一些坑的,记下来免得忘记了。

功能:支持 Titile,Message,1个或2个按钮。如下:

根据文字动态调整 UILabel 高度_第1张图片

代码:

//
//  TTSMessage.h
//  TTSMessage
//
//  Created by aaron.zheng on 2/12/14.
//  Copyright (c) 2014 aaron.zheng. All rights reserved.
//

#import 

typedef void (^CancelBtnTouchBlock)();
typedef void (^OtherBtnTouchBlock)();

@interface TTSMessage : NSObject
+(void)showMessageViewWithTitle:(NSString*)title message:(NSString*)message cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitle:(NSString*)otherButtonTitle onCancel:(CancelBtnTouchBlock)canceled onOther:(OtherBtnTouchBlock)other;
@end

//
//  TTSMessage.m
//  TTSMessage
//
//  Created by aaron.zheng on 2/12/14.
//  Copyright (c) 2014 aaron.zheng. All rights reserved.
//

#import "TTSMessage.h"
#import 

#define MARGIN 10
#define MARGIN_L 10
#define MARGIN_R 10
#define BUTTON_HEIGHT 36

static CancelBtnTouchBlock _cancelBtnTouchBlock;
static OtherBtnTouchBlock _otherBtnTouchBlock;

static TTSMessage *_ttsMessage;

@implementation TTSMessage{
    UIView *_view;
    UIView *_contentView;
    
}


-(id)init{
    if ([super init]) {
        _view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    }
    return self;
}

+(void)showMessageViewWithTitle:(NSString*)title message:(NSString*)message cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitle:(NSString*)otherButtonTitle onCancel:(CancelBtnTouchBlock)canceled onOther:(OtherBtnTouchBlock)other{
    
    _cancelBtnTouchBlock = [canceled copy];
    _otherBtnTouchBlock = [other copy];
    
    _ttsMessage = [[TTSMessage alloc] init];
    
    UIImage *blueImage = [UIImage imageNamed:@"image-button_blue.png"];
    blueImage = [blueImage  resizableImageWithCapInsets:UIEdgeInsetsMake(2,2, 2, 2) resizingMode:UIImageResizingModeStretch];
    
    
    UIImage *pressBlueImage = [UIImage imageNamed:@"image-button_blue_highlighted.png"];
    pressBlueImage = [pressBlueImage resizableImageWithCapInsets:UIEdgeInsetsMake(2,2, 2, 2) resizingMode:UIImageResizingModeStretch];
    
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    
    _ttsMessage->_view.frame = [UIScreen mainScreen].bounds;
    _ttsMessage->_view.backgroundColor = [UIColor clearColor];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:_ttsMessage->_view.frame];
    imageView.backgroundColor = [UIColor blackColor];
    imageView.alpha = 0.5;
    [_ttsMessage->_view addSubview:imageView];
    
    [window addSubview:_ttsMessage->_view];
    
    CGRect newRect;
    CGRect mainRect = [UIScreen mainScreen].bounds;
    _ttsMessage->_contentView = [[UIView alloc] initWithFrame:CGRectMake(MARGIN, 0, _ttsMessage->_view.frame.size.width - 2*MARGIN, 100)];
    _ttsMessage->_contentView.backgroundColor = [UIColor whiteColor];
    _ttsMessage->_contentView.layer.cornerRadius = 5.0f;
    
    UILabel *titleLabel;
    if (title != nil && ![title isEqualToString:@""]) {
        newRect = CGRectMake(MARGIN_L, MARGIN, _ttsMessage->_contentView.frame.size.width - 2*MARGIN_L,23);
        titleLabel = [[UILabel alloc] initWithFrame:newRect]; //同下描述。
        titleLabel.textAlignment = UITextAlignmentCenter;
        titleLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:FONT_SIZE_DIALOG_TITLE_TEXT];
        titleLabel.layer.masksToBounds = YES;
        titleLabel.layer.cornerRadius = 3.0f;
        titleLabel.backgroundColor = [UIColor grayColor];
        titleLabel.text = title;
        newRect.size.height = [_ttsMessage expectedHeight:titleLabel andFontSize:17];
        titleLabel.frame = newRect;
        [_ttsMessage->_contentView addSubview:titleLabel];
    }
    
    UILabel *messageLabel;
    if (message != nil && ![message isEqualToString:@""]) {
        newRect = CGRectMake(MARGIN_L, MARGIN + titleLabel.frame.size.height + MARGIN, _ttsMessage->_contentView.frame.size.width - 2*MARGIN_L, 21);
        messageLabel = [[UILabel alloc] initWithFrame:newRect]; //如果 alloc 的时候不初始化 label 的高度的话,在接下来调用[self expectedHeight: andFontSize:]的时候会出现计算高度偏小,导致文字显示不完全。
        messageLabel.layer.masksToBounds = YES;
        messageLabel.layer.cornerRadius = 3.0f;
        messageLabel.textAlignment = UITextAlignmentCenter;
//        messageLabel.backgroundColor = [UIColor grayColor];
        messageLabel.text = message;
        newRect.size.height = [_ttsMessage expectedHeight:messageLabel andFontSize:FONT_SIZE_DIALOG_CONTENT_LABEL_TEXT];
        messageLabel.frame = newRect;
        [_ttsMessage->_contentView addSubview:messageLabel];
    }
    
    UIButton *cancelBtn,*otherBtn;
    if ((cancelButtonTitle != nil && ![cancelButtonTitle isEqualToString:@""]) && (otherButtonTitle == nil || [otherButtonTitle isEqualToString:@""])) {
        cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(MARGIN_L, 3*MARGIN + titleLabel.frame.size.height + messageLabel.frame.size.height, _ttsMessage->_contentView.frame.size.width - 2*MARGIN_L, BUTTON_HEIGHT)];
        cancelBtn.layer.masksToBounds = YES;
        cancelBtn.layer.cornerRadius = 3.0f;
        [cancelBtn setBackgroundImage:blueImage  forState:UIControlStateNormal];
        [cancelBtn setBackgroundImage:pressBlueImage forState:UIControlStateHighlighted];
        cancelBtn.titleLabel.font = [UIFont systemFontOfSize:FONT_SIZE_GREY_BUTTON_TEXT];
        [cancelBtn addTarget:self action:@selector(cancelBtnTouch) forControlEvents:UIControlEventTouchUpInside];
        cancelBtn.backgroundColor = [UIColor grayColor];
        [cancelBtn setTitle:cancelButtonTitle forState:UIControlStateNormal];
        [_ttsMessage->_contentView addSubview:cancelBtn];
    }else if(cancelButtonTitle != nil && ![cancelButtonTitle isEqualToString:@""] && otherButtonTitle != nil && ![otherButtonTitle isEqualToString:@""]){
        cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(MARGIN_L,3*MARGIN + titleLabel.frame.size.height + messageLabel.frame.size.height , (_ttsMessage->_contentView.frame.size.width -3*MARGIN_L)/2.0, BUTTON_HEIGHT)];
        cancelBtn.layer.masksToBounds = YES;
        cancelBtn.layer.cornerRadius = 3.0f;
        [cancelBtn setBackgroundImage:blueImage  forState:UIControlStateNormal];
        [cancelBtn setBackgroundImage:pressBlueImage forState:UIControlStateHighlighted];
        [cancelBtn addTarget:self action:@selector(cancelBtnTouch) forControlEvents:UIControlEventTouchUpInside];
        cancelBtn.backgroundColor = [UIColor grayColor];
        [cancelBtn setTitle:cancelButtonTitle forState:UIControlStateNormal];
        [_ttsMessage->_contentView addSubview:cancelBtn];
        
        otherBtn = [[UIButton alloc] initWithFrame:CGRectMake(2*MARGIN_L + cancelBtn.frame.size.width,3*MARGIN + titleLabel.frame.size.height + messageLabel.frame.size.height , (_ttsMessage->_contentView.frame.size.width -3*MARGIN_L)/2.0, BUTTON_HEIGHT)];
        otherBtn.layer.masksToBounds = YES;
        otherBtn.layer.cornerRadius = 3.0f;
        [otherBtn setBackgroundImage:blueImage  forState:UIControlStateNormal];
        [otherBtn setBackgroundImage:pressBlueImage forState:UIControlStateHighlighted];
        [otherBtn addTarget:self action:@selector(otherBtnTouch) forControlEvents:UIControlEventTouchUpInside];
        otherBtn.backgroundColor = [UIColor grayColor];
        [otherBtn setTitle:otherButtonTitle forState:UIControlStateNormal];
        [_ttsMessage->_contentView addSubview:otherBtn];
    }
    
    newRect = _ttsMessage->_contentView.bounds;
    newRect.size.height = 4*MARGIN + titleLabel.frame.size.height + messageLabel.frame.size.height + cancelBtn.frame.size.height;
    newRect.origin.x = MARGIN_L;
    newRect.origin.y = (mainRect.size.height - _ttsMessage->_contentView.frame.size.height)/2.0 - _ttsMessage->_contentView.frame.size.height/2.0;
    _ttsMessage->_contentView.frame = newRect;
    
    
    [_ttsMessage->_view addSubview:_ttsMessage->_contentView];
    
}

+(void)cancelBtnTouch{
    _cancelBtnTouchBlock();
    [_ttsMessage->_view removeFromSuperview];
}

+(void)otherBtnTouch{
    _otherBtnTouchBlock();
    [_ttsMessage->_view removeFromSuperview];
}

-(float)expectedHeight:(UILabel*)label andFontSize:(int)fontSize{
    [label setNumberOfLines:0];
    [label setLineBreakMode:NSLineBreakByCharWrapping];
    
    UIFont *font = [UIFont systemFontOfSize:fontSize];
    
    NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                          font, NSFontAttributeName,
                                          nil];
    
    CGSize maximumLabelSize = CGSizeMake(_contentView.frame.size.width - 2*MARGIN,9999);
    
    CGRect expectedLabelRect = [label.text boundingRectWithSize:maximumLabelSize
                                                         options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                                      attributes:attributesDictionary
                                                         context:nil];
    CGSize *expectedLabelSize = &expectedLabelRect.size;
    
    return expectedLabelSize->height + label.frame.size.height;
}

@end

使用:

[TTSMessage showMessageViewWithTitle:@"" message:@"渔家傲(辛弃疾):风月小斋模画舫。绿窗朱户江湖样。酒是短桡歌是桨。和情放。醉乡稳到无风浪。自有拍浮千斛酿。从教日日蒲桃涨。门外独醒人也访。同俯仰。赏心却在鸱夷上。" cancelButtonTitle:@"OK" otherButtonTitle:@"cancel" onCancel:^{
        NSLog(@"onCancel called..");
    } onOther:^{
        NSLog(@"onOther called..");
    }];


之前是需要 alloc 一个TTSMessage 之后再调用接口的,感觉接口的调用不是很方便,现在把它接口改为静态方法,调用起来就方便多了,当然,你也可以考虑把它写成UIViewController分类或者是UIView的分类,这样就可以直接用self 或者self.view 来调用了,反正看使用方便吧。

参考:UILabel - auto-size label to fit text?


//-----------------------------------------------------------------分割线--2014-04-15 再次编辑--------------------------------------------------------------

在看 AFNetworking 源码的时候有一段代码是计算 cell 高度的,也许以后会用到,mark 下来先。

- (CGFloat)tableView:(__unused UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [PostTableViewCell heightForCellWithPost:[self.posts objectAtIndex:(NSUInteger)indexPath.row]];
}

+ (CGFloat)heightForCellWithPost:(Post *)post {
    return (CGFloat)fmaxf(70.0f, (float)[self detailTextHeight:post.text] + 45.0f);
}

+ (CGFloat)detailTextHeight:(NSString *)text {
    CGRect rectToFit = [text boundingRectWithSize:CGSizeMake(240.0f, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0f]} context:nil];
    return rectToFit.size.height;
}



你可能感兴趣的:(iOS)