iOS開(kāi)發(fā)-帶Placeholder的UITextView實(shí)現(xiàn)

剛從事這個(gè)行業(yè)的時(shí)候囚枪,想在UITextView上加Placeholder這個(gè)功能上為難了一下咆槽,然后各種查陈轿,也在他人的博客、簡(jiǎn)書(shū)上留言來(lái)尋找答案秦忿。但是實(shí)現(xiàn)起來(lái)都差強(qiáng)人意麦射。后來(lái)偶然的情況下找到了封裝好的類簇,用起來(lái)非常方便灯谣。最近有挺多新手也遇到這樣的問(wèn)題潜秋,通過(guò)我之前在他人博客上留的郵箱老找到我的QQ詢問(wèn)我是如何解決的。我想想還是把他放在網(wǎng)絡(luò)上比較好胎许。

UITextView+Placeholder.h
#import <UIKit/UIKit.h>

@interface UITextView (Placeholder)

@property (nonatomic, readonly) UILabel *placeholderLabel;

@property (nonatomic, strong) NSString *placeholder;
@property (nonatomic, strong) NSAttributedString *attributedPlaceholder;
@property (nonatomic, strong) UIColor *placeholderColor;

+ (UIColor *)defaultPlaceholderColor;

@end

UITextView+Placeholder.m

#import <objc/runtime.h>
#import "UITextView+Placeholder.h"

@implementation UITextView (Placeholder)

#pragma mark - Swizzle Dealloc

+ (void)load {
// is this the best solution?
method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"dealloc")),
                               class_getInstanceMethod(self.class, @selector(swizzledDealloc)));
}

- (void)swizzledDealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
UILabel *label = objc_getAssociatedObject(self, @selector(placeholderLabel));
if (label) {
    for (NSString *key in self.class.observingKeys) {
        @try {
            [self removeObserver:self forKeyPath:key];
        }
        @catch (NSException *exception) {
            // Do nothing
        }
    }
}
[self swizzledDealloc];
}

#pragma mark - Class Methods
#pragma mark `defaultPlaceholderColor`

+ (UIColor *)defaultPlaceholderColor {
static UIColor *color = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    UITextField *textField = [[UITextField alloc] init];
    textField.placeholder = @" ";
    color = [textField valueForKeyPath:@"_placeholderLabel.textColor"];
});
return color;
}

#pragma mark - `observingKeys`

+ (NSArray *)observingKeys {
return @[@"attributedText",
         @"bounds",
         @"font",
         @"frame",
         @"text",
         @"textAlignment",
         @"textContainerInset"];
}

#pragma mark - Properties
#pragma mark `placeholderLabel`

- (UILabel *)placeholderLabel {
UILabel *label = objc_getAssociatedObject(self, @selector(placeholderLabel));
if (!label) {
    NSAttributedString *originalText = self.attributedText;
    self.text = @" "; // lazily set font of `UITextView`.
    self.attributedText = originalText;

    label = [[UILabel alloc] init];
    label.textColor = [self.class defaultPlaceholderColor];
    label.numberOfLines = 0;
    label.userInteractionEnabled = NO;
    objc_setAssociatedObject(self, @selector(placeholderLabel), label, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(updatePlaceholderLabel)
                                                 name:UITextViewTextDidChangeNotification
                                               object:self];

    for (NSString *key in self.class.observingKeys) {

        [self addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew context:nil];
    }
}
  return label;
}

#pragma mark `placeholder`

- (NSString *)placeholder {
    return self.placeholderLabel.text;
}

- (void)setPlaceholder:(NSString *)placeholder {

    self.placeholderLabel.text = placeholder;
    [self updatePlaceholderLabel];
}

- (NSAttributedString *)attributedPlaceholder {
return self.placeholderLabel.attributedText;
}

- (void)setAttributedPlaceholder:(NSAttributedString *)attributedPlaceholder {
self.placeholderLabel.attributedText = attributedPlaceholder;
[self updatePlaceholderLabel];
}

#pragma mark `placeholderColor`

- (UIColor *)placeholderColor {
return self.placeholderLabel.textColor;
}

- (void)setPlaceholderColor:(UIColor *)placeholderColor {
self.placeholderLabel.textColor = placeholderColor;
}
#pragma mark - KVO

- (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context {
[self updatePlaceholderLabel];
}

#pragma mark - Update

- (void)updatePlaceholderLabel {
if (self.text.length) {
    [self.placeholderLabel removeFromSuperview];
    return;
}

[self insertSubview:self.placeholderLabel atIndex:0];

self.placeholderLabel.font = self.font;
self.placeholderLabel.textAlignment = self.textAlignment;

// `NSTextContainer` is available since iOS 7
CGFloat lineFragmentPadding;
UIEdgeInsets textContainerInset;

#pragma deploymate push "ignored-api-availability"
// iOS 7+
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
    lineFragmentPadding = self.textContainer.lineFragmentPadding;
    textContainerInset = self.textContainerInset;
}
#pragma deploymate pop

// iOS 6
else {
    lineFragmentPadding = 5;
    textContainerInset = UIEdgeInsetsMake(8, 0, 8, 0);
}

CGFloat x = lineFragmentPadding + textContainerInset.left;
CGFloat y = textContainerInset.top;
CGFloat width = CGRectGetWidth(self.bounds) - x - lineFragmentPadding - textContainerInset.right;
CGFloat height = [self.placeholderLabel sizeThatFits:CGSizeMake(width, 0)].height;
self.placeholderLabel.frame = CGRectMake(x, y, width, height);
}

@end

iOS中UITextField帶有PlaceHolder屬性峻呛,可以方便用于提示輸入。但是同樣可以進(jìn)行文本輸入的UITextView控件則沒(méi)有PlaceHolder屬性辜窑,還是有些不方便的钩述。
使用方法:把文件引入工程中然后直接用屬性placeHolder就可以實(shí)現(xiàn)效果。

核心思路就是使用2個(gè)UITextView來(lái)模擬PlaceHolder的效果,其中做為輸入?yún)^(qū)域的TextView在表面,背景要設(shè)為透明,作為PlaceHolder角色的TextView則在底層,兩者通過(guò)UITextViewDelegate來(lái)動(dòng)態(tài)控制由捎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖最筒,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贺氓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)辙培,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)蔑水,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人扬蕊,你說(shuō)我怎么就攤上這事搀别。” “怎么了尾抑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵歇父,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我再愈,道長(zhǎng)榜苫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任翎冲,我火速辦了婚禮垂睬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抗悍。我一直安慰自己驹饺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布缴渊。 她就那樣靜靜地躺著赏壹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疟暖。 梳的紋絲不亂的頭發(fā)上卡儒,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音俐巴,去河邊找鬼骨望。 笑死,一個(gè)胖子當(dāng)著我的面吹牛欣舵,可吹牛的內(nèi)容都是我干的擎鸠。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缘圈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼劣光!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起糟把,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绢涡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后遣疯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體雄可,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了数苫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聪舒。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖虐急,靈堂內(nèi)的尸體忽然破棺而出箱残,到底是詐尸還是另有隱情,我是刑警寧澤止吁,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布被辑,位于F島的核電站,受9級(jí)特大地震影響赏殃,放射性物質(zhì)發(fā)生泄漏敷待。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一仁热、第九天 我趴在偏房一處隱蔽的房頂上張望榜揖。 院中可真熱鬧,春花似錦抗蠢、人聲如沸举哟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妨猩。三九已至,卻和暖如春秽褒,著一層夾襖步出監(jiān)牢的瞬間壶硅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工销斟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庐椒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓蚂踊,卻偏偏與公主長(zhǎng)得像约谈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子犁钟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容