Skip to content

Commit 5aa12d9

Browse files
committed
feat(ios): add paragraph styles support for TextInput
TextInput Current support: 1.lineHeight 2.lineSpacing 3.lineHeightMultiple
1 parent c151da3 commit 5aa12d9

File tree

9 files changed

+187
-11
lines changed

9 files changed

+187
-11
lines changed

driver/js/examples/hippy-react-demo/src/components/TextInput/index.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ const styles = StyleSheet.create({
2020
fontSize: 16,
2121
color: '#242424',
2222
height: 30,
23+
// you can use lineHeight/lineSpacing/lineHeightMultiple
24+
// to control the space between lines in multi-line input.(iOS only for now)
25+
// for example:
2326
lineHeight: 30,
27+
// lineSpacing: 50,
28+
// lineHeightMultiple: 1.5,
2429
},
2530
input_style_block: {
2631
height: 100,

driver/js/examples/hippy-vue-demo/src/components/demos/demo-textarea.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export default {
9494
underline-color-android: #40b883;
9595
placeholder-text-color: #666;
9696
align-self: center;
97+
/* you can use line-height/line-spacing/line-height-multiple */
98+
/* to control the space between lines in multi-line input. (iOS only for now) */
99+
line-height: 30;
100+
/*line-spacing: 20;*/
101+
/*line-height-multiple: 1.5;*/
97102
}
98103
99104
#demo-textarea .output {

renderer/native/ios/renderer/component/textinput/HippyShadowTextView.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,12 @@
2828
@property (nonatomic, copy) NSString *placeholder;
2929

3030
@property (nonatomic, strong) UIFont *font;
31+
32+
/// ParagraphStyles - lineHeight
33+
@property (nonatomic, strong) NSNumber *lineHeight;
34+
/// ParagraphStyles - lineSpacing
35+
@property (nonatomic, strong) NSNumber *lineSpacing;
36+
/// ParagraphStyles - lineHeightMultiple
37+
@property (nonatomic, strong) NSNumber *lineHeightMultiple;
38+
3139
@end

renderer/native/ios/renderer/component/textinput/HippyShadowTextView.mm

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,18 @@
2323
#import "HippyUtils.h"
2424
#import "HippyShadowTextView.h"
2525
#import "HippyShadowView+Internal.h"
26-
2726
#include "dom/dom_manager.h"
2827
#include "dom/dom_node.h"
2928
#include "dom/layout_node.h"
3029

30+
/// Default font size of TextView
31+
/// Note that in `HippyFont` it is defined as 14,
32+
/// For the sake of compatibility, keep it the way it is.
33+
static const CGFloat defaultFontSize = 16.0;
34+
3135
@interface HippyShadowTextView ()
3236

37+
/// Cached text attributes
3338
@property (nonatomic, strong) NSDictionary *dicAttributes;
3439

3540
@end
@@ -40,15 +45,35 @@ @interface HippyShadowTextView ()
4045
hippy::LayoutMeasureMode heightMeasureMode, void *layoutContext) {
4146
hippy::LayoutSize result;
4247
if (weakShadowText) {
43-
HippyShadowTextView *strongShadowText = weakShadowText;
44-
NSString *text = strongShadowText.text ?: strongShadowText.placeholder;
45-
if (nil == strongShadowText.dicAttributes) {
46-
if (strongShadowText.font == nil) {
47-
strongShadowText.font = [UIFont systemFontOfSize:16];
48+
HippyShadowTextView *shadowText = weakShadowText;
49+
NSString *text = shadowText.text ?: shadowText.placeholder;
50+
if (nil == shadowText.dicAttributes) {
51+
if (shadowText.font == nil) {
52+
53+
shadowText.font = [UIFont systemFontOfSize:defaultFontSize];
54+
}
55+
NSDictionary *attrs = nil;
56+
if ((id)shadowText.lineHeight != nil ||
57+
(id)shadowText.lineSpacing != nil ||
58+
(id)shadowText.lineHeightMultiple != nil) {
59+
// Add paragraphStyle
60+
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
61+
if ((id)shadowText.lineHeight != nil) {
62+
paragraphStyle.minimumLineHeight = [shadowText.lineHeight doubleValue];
63+
paragraphStyle.maximumLineHeight = [shadowText.lineHeight doubleValue];
64+
} else if ((id)shadowText.lineSpacing != nil) {
65+
paragraphStyle.lineSpacing = [shadowText.lineSpacing doubleValue];
66+
} else if ((id)shadowText.lineHeightMultiple != nil) {
67+
paragraphStyle.lineHeightMultiple = [shadowText.lineHeightMultiple doubleValue];
68+
}
69+
attrs = @{ NSFontAttributeName: shadowText.font,
70+
NSParagraphStyleAttributeName : paragraphStyle };
71+
} else {
72+
attrs = @{ NSFontAttributeName: shadowText.font };
4873
}
49-
strongShadowText.dicAttributes = @ { NSFontAttributeName: strongShadowText.font };
74+
shadowText.dicAttributes = attrs;
5075
}
51-
CGSize computedSize = [text sizeWithAttributes:strongShadowText.dicAttributes];
76+
CGSize computedSize = [text sizeWithAttributes:shadowText.dicAttributes];
5277
result.width = ceil(computedSize.width);
5378
result.height = ceil(computedSize.height);
5479
}

renderer/native/ios/renderer/component/textinput/HippyTextField.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,11 @@
6565
@property (nonatomic, copy) NSString *text;
6666
@property (nonatomic, strong) UIColor *textColor;
6767

68+
/// ParagraphStyles - lineHeight
69+
@property (nonatomic, strong) NSNumber *lineHeight;
70+
/// ParagraphStyles - lineSpacing
71+
@property (nonatomic, strong) NSNumber *lineSpacing;
72+
/// ParagraphStyles - lineHeightMultiple
73+
@property (nonatomic, strong) NSNumber *lineHeightMultiple;
74+
6875
@end

renderer/native/ios/renderer/component/textinput/HippyTextField.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ @implementation HippyTextField {
119119
HippyUITextField *_textView;
120120
}
121121

122+
@dynamic lineHeight;
123+
@dynamic lineSpacing;
124+
@dynamic lineHeightMultiple;
125+
122126
- (void)keyboardWillShow:(NSNotification *)aNotification {
123127
[super keyboardWillShow:aNotification];
124128
NSDictionary *userInfo = [aNotification userInfo];
@@ -427,4 +431,19 @@ - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRang
427431
return YES;
428432
}
429433

434+
435+
#pragma mark - LineHeight Related
436+
437+
- (void)setLineHeight:(NSNumber *)lineHeight {
438+
// LineHeight does not take effect on single-line input.
439+
}
440+
441+
- (void)setLineSpacing:(NSNumber *)lineSpacing {
442+
// LineSpacing does not take effect on single-line input.
443+
}
444+
445+
- (void)setLineHeightMultiple:(NSNumber *)lineHeightMultiple {
446+
// LineHeightMultiple does not take effect on single-line input.
447+
}
448+
430449
@end

renderer/native/ios/renderer/component/textinput/HippyTextView.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@
6262
@property (nonatomic, copy) NSString *value;
6363
@property (nonatomic, strong) NSString *defaultValue;
6464
@property (nonatomic, strong) UIColor *textColor;
65+
66+
/// ParagraphStyles - lineHeight
67+
@property (nonatomic, strong) NSNumber *lineHeight;
68+
/// ParagraphStyles - lineSpacing
69+
@property (nonatomic, strong) NSNumber *lineSpacing;
70+
/// ParagraphStyles - lineHeightMultiple
71+
@property (nonatomic, strong) NSNumber *lineHeightMultiple;
72+
6573
@property (nonatomic, copy) HippyDirectEventBlock onChangeText;
6674
@property (nonatomic, copy) HippyDirectEventBlock onBlur;
6775
@property (nonatomic, copy) HippyDirectEventBlock onFocus;

renderer/native/ios/renderer/component/textinput/HippyTextView.mm

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ - (void)setCaretColor:(UIColor*)color{
7373
@end
7474

7575
@interface HippyTextView () <NativeRenderUITextViewResponseDelegate>
76+
77+
/// ParagraphStyle for TextView and PlaceholderView,
78+
/// used for lineHeight config and etc.
79+
@property (nonatomic, strong) NSMutableParagraphStyle *paragraphStyle;
80+
7681
@end
7782

7883
@implementation HippyTextView {
@@ -95,6 +100,10 @@ @implementation HippyTextView {
95100
BOOL _viewDidCompleteInitialLayout;
96101
}
97102

103+
@dynamic lineHeight;
104+
@dynamic lineSpacing;
105+
@dynamic lineHeightMultiple;
106+
98107
#pragma mark - Keyboard Events
99108

100109
- (void)keyboardWillShow:(NSNotification *)aNotification {
@@ -303,11 +312,19 @@ - (void)updatePlaceholder {
303312
_placeholderView.scrollEnabled = NO;
304313
_placeholderView.editable = NO;
305314
_placeholderView.scrollsToTop = NO;
306-
_placeholderView.attributedText = [[NSAttributedString alloc] initWithString:_placeholder attributes:@{
315+
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:_placeholder
316+
attributes:@{
307317
NSFontAttributeName: (_textView.font ? _textView.font : [self defaultPlaceholderFont]),
308-
NSForegroundColorAttributeName: _placeholderTextColor
318+
NSForegroundColorAttributeName: _placeholderTextColor
309319
}];
320+
if (self.paragraphStyle) {
321+
// Apply paragraph style to the entire string
322+
[attrStr addAttribute:NSParagraphStyleAttributeName
323+
value:self.paragraphStyle
324+
range:NSMakeRange(0, attrStr.length)];
325+
}
310326
_placeholderView.textAlignment = _textView.textAlignment;
327+
_placeholderView.attributedText = attrStr;
311328

312329
[self insertSubview:_placeholderView belowSubview:_textView];
313330
[self updatePlaceholderVisibility];
@@ -323,6 +340,40 @@ - (void)setFont:(UIFont *)font {
323340
[self updatePlaceholder];
324341
}
325342

343+
- (void)setLineHeight:(NSNumber *)lineHeight {
344+
// create paragraphStyle, update placeholder and textView
345+
if (!self.paragraphStyle) {
346+
self.paragraphStyle = [[NSMutableParagraphStyle alloc] init];
347+
}
348+
self.paragraphStyle.minimumLineHeight = [lineHeight doubleValue];
349+
self.paragraphStyle.maximumLineHeight = [lineHeight doubleValue];
350+
351+
[self updateParagraphAndFontStyleForTextView:_textView];
352+
[self updatePlaceholder];
353+
}
354+
355+
- (void)setLineSpacing:(NSNumber *)lineSpacing {
356+
// create paragraphStyle, update placeholder and textView
357+
if (!self.paragraphStyle) {
358+
self.paragraphStyle = [[NSMutableParagraphStyle alloc] init];
359+
}
360+
self.paragraphStyle.lineSpacing = [lineSpacing doubleValue];
361+
362+
[self updateParagraphAndFontStyleForTextView:_textView];
363+
[self updatePlaceholder];
364+
}
365+
366+
- (void)setLineHeightMultiple:(NSNumber *)lineHeightMultiple {
367+
// create paragraphStyle, update placeholder and textView
368+
if (!self.paragraphStyle) {
369+
self.paragraphStyle = [[NSMutableParagraphStyle alloc] init];
370+
}
371+
self.paragraphStyle.lineHeightMultiple = [lineHeightMultiple doubleValue];
372+
373+
[self updateParagraphAndFontStyleForTextView:_textView];
374+
[self updatePlaceholder];
375+
}
376+
326377
- (void)setPlaceholder:(NSString *)placeholder {
327378
_placeholder = placeholder;
328379
[self updatePlaceholder];
@@ -416,7 +467,8 @@ - (void)setText:(NSString *)text {
416467
NSInteger oldTextLength = _textView.text.length;
417468

418469
_predictedText = text;
419-
_textView.text = text;
470+
// Use `attribuedText` instead of `text` to show paragraphStyle
471+
_textView.attributedText = [self attributedTextAfterApplyingParagraphStyle:text];
420472
[self textViewDidChange:_textView];
421473
if (selection.empty) {
422474
// maintain cursor position relative to the end of the old text
@@ -473,6 +525,8 @@ - (void)textViewDidBeginEditing:(__unused UITextView *)textView {
473525
_textView.text = @"";
474526
[self updatePlaceholderVisibility];
475527
}
528+
// update typingAttributes
529+
[self updateTypingAttributes];
476530
}
477531

478532
static BOOL findMismatch(NSString *first, NSString *second, NSRange *firstRange, NSRange *secondRange) {
@@ -740,4 +794,43 @@ - (void)setTextViewKeyboardAppearance {
740794
}
741795
}
742796

797+
#pragma mark - ParagraphStyle Related
798+
799+
- (void)updateTypingAttributes {
800+
if (self.paragraphStyle) {
801+
// Set typingAttributes if needed
802+
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
803+
attrs[NSParagraphStyleAttributeName] = self.paragraphStyle;
804+
if (_textView.font) {
805+
attrs[NSFontAttributeName] = _textView.font;
806+
}
807+
_textView.typingAttributes = attrs;
808+
}
809+
}
810+
811+
- (NSAttributedString *)attributedTextAfterApplyingParagraphStyle:(NSString *)text {
812+
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];
813+
814+
if (self.paragraphStyle) {
815+
// add paragraph style to the entire string
816+
[attributedString addAttribute:NSParagraphStyleAttributeName
817+
value:self.paragraphStyle
818+
range:NSMakeRange(0, attributedString.length)];
819+
}
820+
if (_textView.font) {
821+
// add font style to the entire string
822+
[attributedString addAttribute:NSFontAttributeName
823+
value:_textView.font
824+
range:NSMakeRange(0, attributedString.length)];
825+
}
826+
return attributedString;
827+
}
828+
829+
- (void)updateParagraphAndFontStyleForTextView:(UITextView *)textView {
830+
if (textView.text.length == 0) {
831+
return;
832+
}
833+
textView.attributedText = [self attributedTextAfterApplyingParagraphStyle:textView.text];
834+
}
835+
743836
@end

renderer/native/ios/renderer/component/textinput/HippyTextViewManager.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,13 @@ - (HippyShadowView *)shadowView {
146146

147147
HIPPY_EXPORT_SHADOW_PROPERTY(text, NSString)
148148
HIPPY_EXPORT_SHADOW_PROPERTY(placeholder, NSString)
149+
HIPPY_EXPORT_SHADOW_PROPERTY(lineHeight, NSNumber)
150+
HIPPY_EXPORT_SHADOW_PROPERTY(lineSpacing, NSNumber)
151+
HIPPY_EXPORT_SHADOW_PROPERTY(lineHeightMultiple, NSNumber)
149152

153+
HIPPY_EXPORT_VIEW_PROPERTY(lineHeight, NSNumber)
154+
HIPPY_EXPORT_VIEW_PROPERTY(lineSpacing, NSNumber)
155+
HIPPY_EXPORT_VIEW_PROPERTY(lineHeightMultiple, NSNumber)
150156
HIPPY_REMAP_VIEW_PROPERTY(autoCapitalize, textView.autocapitalizationType, UITextAutocapitalizationType)
151157
HIPPY_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
152158
HIPPY_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)

0 commit comments

Comments
 (0)