iOS開發筆記 | 自定義具有內邊距的label

weixin_34120274發表於2017-12-07
1692043-e57db9fde46249fd.png
iu

前言

UIScrollViewcontentInset這個屬性,但是UILabel沒有;Android有,iOS沒有。

最近需要用到帶內邊距的label,所以就結合網上前輩的程式碼封裝了一個,本來我是想弄一個category的,但最終失敗了。

1692043-048d30f499f034ce.jpg

程式碼如下,繼承自UILabel

.h檔案:

#import <UIKit/UIKit.h>

@interface EdgeInsetsLabel : UILabel

@property (nonatomic) UIEdgeInsets contentInset;

@end

.m檔案:

#import "EdgeInsetsLabel.h"

@implementation EdgeInsetsLabel

- (void)setContentInset:(UIEdgeInsets)contentInset {
    _contentInset = contentInset;
    NSString *tempString = self.text;
    self.text = @"";
    self.text = tempString;
}

-(void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.contentInset)];
}

@end

使用

self.label.contentInset = UIEdgeInsetsMake(0, 20, 0, 20);

程式碼說明

改變label的inset是在這個方法裡面進行的:

-(void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.contentInset)];
}

這是系統提供的方法:


1692043-8c971d7b19799b37.png

這個方法不能主動呼叫,但我們又需要在這個方法中做處理,怎麼辦?

我實驗了一下,改變label的text的時候會回撥這個方法

也就是說,我們可以通過改變label的text的方式來間接呼叫這個方法

所以就有了這段奇葩的賦值contentInset的程式碼:

- (void)setContentInset:(UIEdgeInsets)contentInset {
    _contentInset = contentInset;
    NSString *tempString = self.text;
    self.text = @"";
    self.text = tempString;
}

先將label文字清空,再重新賦值text,從而達到改變label的text的效果,最終回撥drawTextInRect:方法。

1692043-48dd46e29e057252.jpg
社會社會

這樣我們給label賦值contentInset的時候就能立即看到效果了。

效果GIF:

1692043-aa76f98966ce3b95.gif
效果.gif

對應的程式碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.label = [[EdgeInsetsLabel alloc] initWithFrame:CGRectMake(90, 90, 200, 100)];
    [self.view addSubview:self.label];
    self.label.text = @"人之初,性本善,我最喜歡吃雞蛋。人之初,性本善,我最喜歡吃雞蛋。人之初,性本善,我最喜歡吃雞蛋。人之初,性本善,我最喜歡吃雞蛋。";
    self.label.numberOfLines = 0;
    self.label.backgroundColor = [UIColor orangeColor];
    self.label.contentInset = UIEdgeInsetsMake(0, 20, 0, 20);
    
    // 3秒後改變contentInset
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.label.contentInset = UIEdgeInsetsMake(20, 50, 10, 20);
    });
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.label.contentInset = UIEdgeInsetsMake(0, 80, 0, 20);
    self.label.text = @"因缺思廳";
}

demo

點選獲取DEMO

最後

如果你有更好的方法不要吝惜分享啊。


2017年12月28日更新

根據評論區neghao同學的建議,要呼叫drawTextInRect這個方法可以通過呼叫UILabelsetNeedsDisplay方法來實現。

所以賦值contentInset就可以改成這樣了:

- (void)setContentInset:(UIEdgeInsets)contentInset {
    _contentInset = contentInset;
    
    [self setNeedsDisplay];
}

程式碼已更新到GitHub。

感謝大家的建議。

相關文章