iOS UILabel中文字與邊框間距的自定義

zhf_Zachariah發表於2017-12-13

專案中需要這個效果,於是找度娘,問谷歌,按照其中一位作者的思路自己動手封裝;

自定義一個繼承於UILabel的Label,直接上程式碼;

想到邊距,首先熟悉的一個詞就是UIEdgeInsets

@property(nonatomic, assign) UIEdgeInsets edgeInsets;
複製程式碼

外界可以通過這個屬性來更改我們這個自定義的Label的邊距;

最重要的就是在.m檔案中我們要重寫兩個方法

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines;

- (void)drawTextInRect:(CGRect)rect;
複製程式碼

cmd點選進去之後,你會看見官方給的兩句註釋,大概理解下

// override points. can adjust rect before calling super.
// label has default content mode of UIViewContentModeRedraw
複製程式碼

閱讀iOS官方文件後,其中第一個方法中bounds這個引數給出解釋是

The bounding rectangle of the receiver.
複製程式碼

第二個引數numberOfLines給出的解釋是

The maximum number of lines to use for the label. 
The value 0 indicates there is no maximum number of lines and that the rectangle should encompass all of the text.
複製程式碼

返回值CGRect型別的解釋是

The computed drawing rectangle for the label’s text.
複製程式碼

怎麼用呢?接著看文件

This method should only be overridden by subclasses that
want to change the receiver’s bounding rectangle before performing any other computations. 
Use the value in the numberOfLines 
parameter to limit the height of the returned rectangle to the specified number of lines of text.

This method may be called by the system if there was a prior call to the sizeToFit
or sizeThatFits: method. Note that labels in UITableViewCell
objects are sized based on the cell dimensions, and not a requested size.
複製程式碼

大概意思就是說這是需要在子類中重寫的方法,你不能直接去呼叫這個方法。當你重寫了這個方法之後,使用時應該呼叫sizeToFit這個方法,不然的話,這個方法不會被呼叫。英語不好,湊合著看。

第二個方法 - (void)drawTextInRect:(CGRect)rect; 官方文件也說了

The rectangle in which to draw the text.
複製程式碼

需要一個可以描繪出label的矩形來作為這個方法的引數; 使用方法也說了

You should not call this method directly. 
This method should only be overridden by subclasses that 
want to modify the default drawing behavior for the label’s text.
By the time this method is called, the current graphics context is already configured with 
the default environment and text color for drawing. 
In your overridden method, you can configure the current context further and then invoke super
to do the actual drawing or you can do the drawing yourself. 
If you do render the text yourself, you should not invoke super
複製程式碼

大概就是說這個也是你不能直接呼叫的方法,需要在子類中重寫。呼叫此方法的時候,當前圖形上下文已經配置了預設的繪圖環境和文字顏色。如果不是自己渲染的話,呼叫[super drawTextInRect:rect];

看了之後我們就重寫方法即可

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
    UIEdgeInsets insets = self.edgeInsets;
    CGRect rect = [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, insets)
                    limitedToNumberOfLines:numberOfLines];
    
    rect.origin.x    -= insets.left;
    rect.origin.y    -= insets.top;
    rect.size.width  += (insets.left + insets.right);
    rect.size.height += (insets.top + insets.bottom);
    
    return rect;
}

- (void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)];
}
複製程式碼

其中UIEdgeInsetsInsetRect表示在原來的rect基礎上根據邊緣距離內切一個rect出來;

然後在需要建立內切Label的時候建立,給之前自定義的屬性賦值

showLabel.edgeInsets = UIEdgeInsetsMake(8, 8+2, 8, 8+2);//設定內邊距
複製程式碼

根據官方文件的說法,我們還得呼叫一下

[showLabel sizeToFit];//重新計算尺寸,會執行Label內重寫的方法
複製程式碼

其他設定跟普通label一樣,到此大功告成!

相關文章