7
7
8
8
#import " MPTextView.h"
9
9
10
- // Manually-selected label offset to align placeholder label with real text.
10
+ // Manually-selected label offsets to align placeholder label with text entry .
11
11
static CGFloat const kLabelLeftOffset = 8 .f;
12
+ static CGFloat const kLabelTopOffset = 0 .f;
13
+
14
+ // When instantiated from IB, the text view has an 8 point top offset:
15
+ static CGFloat const kLabelTopOffsetFromIB = 8 .f;
16
+ // On retina iPhones and iPads, the label is offset by 0.5 points:
12
17
static CGFloat const kLabelTopOffsetRetina = 0 .5f ;
13
18
14
19
@interface MPTextView ()
15
20
16
21
@property (nonatomic , strong ) UILabel *placeholderLabel;
17
22
18
- // Calculate and save the label's left and top offset.
19
- @property (nonatomic , assign ) CGSize labelOffset;
23
+ // The top offset differs when the view is instantiated from IB or programmatically.
24
+ // Use this to track the instantiation route and offset the label accordingly.
25
+ @property (nonatomic , assign ) CGFloat topLabelOffset;
20
26
21
27
// Handle text changed event so we can update the placeholder appropriately
22
28
- (void )textChanged : (NSNotification *)note ;
@@ -31,23 +37,26 @@ @implementation MPTextView
31
37
- (id )initWithCoder : (NSCoder *)aDecoder {
32
38
self = [super initWithCoder: aDecoder];
33
39
if (self) {
40
+ // Account for IB offset:
41
+ _topLabelOffset = kLabelTopOffsetFromIB ;
34
42
[self finishInitialization ];
35
43
}
36
44
return self;
37
45
}
38
46
39
-
40
47
- (id )initWithFrame : (CGRect )frame {
41
48
self = [super initWithFrame: frame];
42
49
if (self) {
50
+ _topLabelOffset = kLabelTopOffset ;
43
51
[self finishInitialization ];
44
52
}
45
53
return self;
46
54
}
47
55
48
-
49
56
// Private method for finishing initialization.
50
- // Rather than muck with designated initializers, let's do it the easy way.
57
+ // Since this class isn't documented for subclassing,
58
+ // I don't feel comfortable changing the initializer chain.
59
+ // Let's do it this way rather than overriding UIView's designated initializer.
51
60
- (void )finishInitialization {
52
61
// Sign up for notifications for text changes:
53
62
[[NSNotificationCenter defaultCenter ] addObserver: self
@@ -56,44 +65,48 @@ - (void)finishInitialization {
56
65
object: self ];
57
66
58
67
CGFloat labelLeftOffset = kLabelLeftOffset ;
59
- CGFloat labelTopOffset = 0 .f ;
68
+ // Use our calculated label offset from initWith…:
69
+ CGFloat labelTopOffset = self.topLabelOffset ;
60
70
61
71
// On retina iPhones and iPads, the label is offset by 0.5 points.
62
72
if ([[UIScreen mainScreen ] scale ] == 2.0 ) {
63
- labelTopOffset = kLabelTopOffsetRetina ;
73
+ labelTopOffset + = kLabelTopOffsetRetina ;
64
74
}
65
- self.labelOffset = CGSizeMake (labelLeftOffset, labelTopOffset);
66
75
67
- [self createPlaceholderLabel ];
76
+ CGSize labelOffset = CGSizeMake (labelLeftOffset, labelTopOffset);
77
+ CGRect labelFrame = [self placeholderLabelFrameWithOffset: labelOffset];
78
+ [self createPlaceholderLabel: labelFrame];
68
79
}
69
80
70
81
71
- #pragma mark - Placeholder label helper
82
+ #pragma mark - Placeholder label helpers
72
83
73
84
// Create our label:
74
- - (void )createPlaceholderLabel {
75
- CGRect labelFrame = [self calculatePlaceholderLabelFrame ];
76
-
85
+ - (void )createPlaceholderLabel : (CGRect )labelFrame {
77
86
self.placeholderLabel = [[UILabel alloc ] initWithFrame: labelFrame];
78
87
self.placeholderLabel .lineBreakMode = NSLineBreakByWordWrapping;
79
88
self.placeholderLabel .numberOfLines = 0 ;
80
89
self.placeholderLabel .font = self.font ;
81
90
self.placeholderLabel .backgroundColor = [UIColor clearColor ];
82
91
self.placeholderLabel .text = self.placeholderText ;
83
- // Manually matched to UITextField's placeholder text color.
92
+ // Color- matched to UITextField's placeholder text color:
84
93
self.placeholderLabel .textColor = [UIColor colorWithWhite: 0 .71f alpha: 1 .0f ];
85
94
95
+ // UIKit effects on the UITextView, like selection ranges
96
+ // and the cursor, are done in a view above the text view,
97
+ // so no need to order this below anything else.
98
+ // Add the label as a subview.
86
99
[self addSubview: self .placeholderLabel];
87
100
}
88
101
89
-
90
- - (CGRect )calculatePlaceholderLabelFrame {
91
- return CGRectMake (self.labelOffset .width ,
92
- self.labelOffset .height ,
93
- self.bounds .size .width - (2 * self.labelOffset .width ),
94
- self.bounds .size .height - (2 * self.labelOffset .height ));
102
+ - (CGRect )placeholderLabelFrameWithOffset : (CGSize )labelOffset {
103
+ return CGRectMake (labelOffset.width ,
104
+ labelOffset.height ,
105
+ self.bounds .size .width - (2 * labelOffset.width ),
106
+ self.bounds .size .height - (2 * labelOffset.height ));
95
107
}
96
108
109
+
97
110
#pragma mark - Custom accessors
98
111
99
112
- (void )setPlaceholderText : (NSString *)string {
@@ -105,16 +118,15 @@ - (void)setPlaceholderText:(NSString *)string {
105
118
106
119
#pragma mark - UITextView subclass methods
107
120
108
- // Keep the placeholder label font in sync with the text view's
121
+ // Keep the placeholder label font in sync with the view's text font.
109
122
- (void )setFont : (UIFont *)font {
110
123
// Call super.
111
124
[super setFont: font];
112
125
113
126
self.placeholderLabel .font = self.font ;
114
127
}
115
128
116
-
117
- // Keep placeholder label alignment in sync
129
+ // Keep placeholder label alignment in sync with the view's text alignment.
118
130
- (void )setTextAlignment : (NSTextAlignment )textAlignment {
119
131
// Call super.
120
132
[super setTextAlignment: textAlignment];
@@ -135,13 +147,14 @@ - (id)insertDictationResultPlaceholder {
135
147
// Call super.
136
148
id placeholder = [super insertDictationResultPlaceholder ];
137
149
138
- // Use .hidden (instead of alpha), since these events also trigger
139
- // -[textChanged] (which has a different criteria by which it shows the label)
150
+ // Use -[setHidden] here instead of setAlpha:
151
+ // these events also trigger -[textChanged],
152
+ // which has a different criteria by which it shows the label,
153
+ // but we undeniably know we want this placeholder hidden.
140
154
self.placeholderLabel .hidden = YES ;
141
155
return placeholder;
142
156
}
143
157
144
-
145
158
// Update visibility when dictation ends.
146
159
- (void )removeDictationResultPlaceholder : (id )placeholder willInsertResult : (BOOL )willInsertResult {
147
160
// Call super.
@@ -165,8 +178,7 @@ - (void)updatePlaceholderLabelVisibility {
165
178
}
166
179
}
167
180
168
-
169
- // When text is set or changed, update the label's visibility:
181
+ // When text is set or changed, update the label's visibility.
170
182
171
183
- (void )setText : (NSString *)text {
172
184
// Call super.
@@ -175,10 +187,8 @@ - (void)setText:(NSString *)text {
175
187
[self updatePlaceholderLabelVisibility ];
176
188
}
177
189
178
-
179
190
- (void )textChanged : (NSNotification *)notification {
180
191
[self updatePlaceholderLabelVisibility ];
181
192
}
182
193
183
-
184
194
@end
0 commit comments