三分钟带你实现自定义的UILabel

2018-08-24  本文已影响274人  阿洋12138

UILabel是UIKit中提供的文本视图控件,用于在iOS设备上展示文本的基础控件,系统提供给我们开发者使用的UILabel本身已经具备了非常强大的功能,我这里所谓的自定义UIlabel实际上也是在原基础上做功能的增加,但是增加的过程中用到的方法,实际上还能有更多的使用。

基础概念

在自定义之前首先了解两个方法

再了解两个对象

最后在看看两个系统分类的定义

@interface NSString(NSStringDrawing)
- (CGSize)sizeWithAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attrs NS_AVAILABLE(10_0, 7_0);
- (void)drawAtPoint:(CGPoint)point withAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attrs NS_AVAILABLE(10_0, 7_0);
- (void)drawInRect:(CGRect)rect withAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attrs NS_AVAILABLE(10_0, 7_0);
@end

@interface NSAttributedString(NSStringDrawing)
- (CGSize)size NS_AVAILABLE(10_0, 6_0);
- (void)drawAtPoint:(CGPoint)point NS_AVAILABLE(10_0, 6_0);
- (void)drawInRect:(CGRect)rect NS_AVAILABLE(10_0, 6_0);
@end

在了解这几个定义后就可以开始自定义了

前奏

自定义高性能的圆角

这里虽说是圆角,但是从代码中还是能分析出,我们这实际上是能自定义不规则的图形的,哈哈哈

自定义Label

- (void)drawRect:(CGRect)rect {
    // Drawing code

    UIFont *font = self.font;

    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText];
    //label本身的尺寸
    CGRect bounds = self.bounds;

    //获取label减去内边距剩余的空间
    CGFloat contentW = bounds.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    CGFloat contentH = bounds.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom;
    CGRect contentBounds = CGRectMake(0,
                                      0,
                                      contentW,
                                      contentH);
    
    CGSize currentTextSize = [self ht_sizeOfString:self.text Font:font limitWidth:contentW];
    CGSize nextTextSize = [self ht_sizeOfString:self.text Font:[font fontWithSize:font.pointSize+0.5] limitWidth:contentW];
    
    
    if (self.adjustsFontSizeToFitWidth == YES) {
        
        BOOL isContain = [self ht_contrastSize:currentTextSize destinationSize:contentBounds.size];
        BOOL isNextContain = [self ht_contrastSize:nextTextSize destinationSize:contentBounds.size];
        
        if (isContain && isNextContain) {
            //字体还能增大,且重新计算currentTextSize
            UIFont *newFont = [self ht_contrastAscendingByFont:font destinationSize:contentBounds.size];
            font = newFont;
            currentTextSize = [self ht_sizeOfString:self.text Font:font limitWidth:contentW];
        }else if (!isContain){
            //字体需要缩小,且重新计算currentTextSize  这里也意味着isNextContain==NO
            UIFont *newFont = [self ht_contrastDescendingByFont:font destinationSize:contentBounds.size];
            font = newFont;
            currentTextSize = [self ht_sizeOfString:self.text Font:font limitWidth:contentW];
        }else if (isContain && !isNextContain){
            //意味着字体大小刚刚好,不需要操作
        }
        [attributedText removeAttribute:NSFontAttributeName range:NSMakeRange(0, self.attributedText.length)];
        [attributedText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.attributedText.length)];
    }
    
    CGFloat textRectX = 0 + self.titleEdgeInsets.left;
    CGFloat textRectY = 0 + self.titleEdgeInsets.top;
    CGFloat textRectW = currentTextSize.width;
    CGFloat textRectH = currentTextSize.height;
    
    switch (_contentHorizontalAlignment) {
        case HTTextHorizontalAlignmentTop:
            textRectY = 0 + self.titleEdgeInsets.top;
            break;
        case HTTextHorizontalAlignmentCenter:
            textRectY = bounds.size.height/2.0 - textRectH/2.0;
            break;
        case HTTextHorizontalAlignmentBottom:
            textRectY = bounds.size.height - self.titleEdgeInsets.bottom - textRectH;
            break;
        default:
            textRectY = 0 + self.titleEdgeInsets.top;
            break;
    }

    CGRect textRect = CGRectMake(textRectX, textRectY, textRectW, textRectH);

    /// NSParagraphStyleAttributeName 这个属性影响换行,实际上没什么作用
    [attributedText removeAttribute:NSParagraphStyleAttributeName range:NSMakeRange(0, attributedText.length)];
    [attributedText drawInRect:textRect];
}

/**
 升序查找 大小合适的字体
 
 @param font 原始字体
 @param desSize 目标尺寸
 @return 返回刚好符合目标尺寸的字体
 */
- (UIFont *)ht_contrastAscendingByFont:(UIFont *)font destinationSize:(CGSize)desSize
{
    CGFloat fontSize = _minFontSize;

    for (CGFloat size = fontSize; size < 80; ) {
        UIFont *newFont = [font fontWithSize:size];
        CGSize newTextSize = [self ht_sizeOfString:self.text Font:newFont limitWidth:desSize.width];
        
        UIFont *lastFont = [font fontWithSize:size+0.5];
        CGSize lastTextSize = [self ht_sizeOfString:self.text Font:lastFont limitWidth:desSize.width];
        
        BOOL isContain = [self ht_contrastSize:newTextSize destinationSize:desSize];
        BOOL isLastContain = [self ht_contrastSize:lastTextSize destinationSize:desSize];

        if (isContain && !isLastContain) {
            return newFont;
        }
        size = size + 0.5;
    }
    return [font fontWithSize:80];
}


/**
 降序查找 大小合适的字体

 @param font 原始字体
 @param desSize 目标尺寸
 @return 返回刚好符合目标尺寸的字体
 */
- (UIFont *)ht_contrastDescendingByFont:(UIFont *)font destinationSize:(CGSize)desSize
{
    CGFloat fontSize = font.pointSize;
    for (CGFloat size = fontSize; size>0; ) {
        if (fontSize<=_minFontSize) {
            return [font fontWithSize:_minFontSize];
        }
        UIFont *newFont = [font fontWithSize:size];
        CGSize newTextSize = [self ht_sizeOfString:self.text Font:newFont limitWidth:desSize.width];
        BOOL isContain = [self ht_contrastSize:newTextSize destinationSize:desSize];
        if (isContain) {
            return newFont;
        }
        size = size - 0.5;
    }
    return [font fontWithSize:_minFontSize];
}


/**
 对比rect是否完全被包含在desRect中,如果是则返回YES,否则返回NO

 @param size 需要对比的size
 @param desSize 被对比的desSize
 */
- (BOOL)ht_contrastSize:(CGSize)size destinationSize:(CGSize)desSize
{
    if (size.width<=desSize.width && size.height<=desSize.height) {
        return YES;
    }else
    {
        return NO;
    }
}


-(CGSize)ht_sizeOfString:(NSString *)string Font:(UIFont *)font limitWidth:(CGFloat)width
{
    if (width<=0) {
        width = [UIScreen mainScreen].bounds.size.width;
    }
    CGRect bounds;
    NSDictionary * parameterDict=[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
    bounds=[string boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:parameterDict context:nil];
    return bounds.size;
}
HTLabel *label = [[HTLabel alloc]initWithFrame:CGRectMake(10, 100, 300, 100)];
label.text = @"我这是测试";
label.font = [UIFont systemFontOfSize:30];
label.textColor = [UIColor yellowColor];
label.backgroundColor = [UIColor redColor];
label.contentHorizontalAlignment = HTTextHorizontalAlignmentBottom;
    
label.cornerRadius = 4;
label.roundingCornerType = HTRoundingCornerTypeAllCorners;
label.titleEdgeInsets = UIEdgeInsetsMake(5, 25, 5, 5);
[self.view addSubview:label];
image.png

Demo地址

上一篇下一篇

猜你喜欢

热点阅读