Skip to content

Commit

Permalink
feat: numberOfLines prop on iOS (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
mateusz1913 committed Oct 6, 2021
1 parent 9712d4d commit 3fdddb6
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 27 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,12 @@ Style to apply to each of the item labels.

### `numberOfLines`

On Android, used to truncate the text with an ellipsis after computing the text layout, including line wrapping,
On Android & iOS, used to truncate the text with an ellipsis after computing the text layout, including line wrapping,
such that the total number of lines does not exceed this number. Default is '1'

| Type | Required | Platform |
| ------- | -------- | -------- |
| number | No | Android |
| number | No | Android, iOS |

### `onBlur`

Expand Down
4 changes: 2 additions & 2 deletions example/ios/PickerExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down Expand Up @@ -626,7 +626,7 @@
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand Down
6 changes: 3 additions & 3 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ PODS:
- React-cxxreact (= 0.64.2)
- React-jsi (= 0.64.2)
- React-perflogger (= 0.64.2)
- RNCPicker (1.16.1):
- RNCPicker (2.1.0):
- React-Core
- Yoga (1.14.0)
- YogaKit (1.18.1):
Expand Down Expand Up @@ -454,7 +454,7 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
FBReactNativeSpec: 84eae1db5dca3a17141275c7d629d712c197ce2e
FBReactNativeSpec: 09ba75493e18a703654c11b0a2f4c096fb1c13d5
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
Expand Down Expand Up @@ -488,7 +488,7 @@ SPEC CHECKSUMS:
React-RCTVibration: 24600e3b1aaa77126989bc58b6747509a1ba14f3
React-runtimeexecutor: a9904c6d0218fb9f8b19d6dd88607225927668f9
ReactCommon: 149906e01aa51142707a10665185db879898e966
RNCPicker: 61c7a0645b9e4ac67960aa7f22a3effcecfdfb8d
RNCPicker: f7a40b21b915b7a187624d52f52b7bc2f73ea413
Yoga: 575c581c63e0d35c9a83f4b46d01d63abc1100ac
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a

Expand Down
4 changes: 4 additions & 0 deletions ios/RNCPicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#import <React/UIView+React.h>

#import "RNCPickerLabel.h"

@interface RNCPicker : UIPickerView

@property (nonatomic, copy) NSArray<NSDictionary *> *items;
Expand All @@ -18,6 +20,8 @@
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) NSTextAlignment textAlign;

@property (nonatomic, assign) NSInteger numberOfLines;

@property (nonatomic, copy) RCTBubblingEventBlock onChange;

@end
50 changes: 38 additions & 12 deletions ios/RNCPicker.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ - (instancetype)initWithFrame:(CGRect)frame
_font = [UIFont systemFontOfSize:21]; // TODO: selected title default should be 23.5
_selectedIndex = NSNotFound;
_textAlign = NSTextAlignmentCenter;
_numberOfLines = 1;
self.delegate = self;
self.dataSource = self;
[self selectRow:0 inComponent:0 animated:YES]; // Workaround for missing selection indicator lines (see https://stackoverflow.com/questions/39564660/uipickerview-selection-indicator-not-visible-in-ios10)
Expand All @@ -48,6 +49,20 @@ - (void)setSelectedIndex:(NSInteger)selectedIndex
}
}

- (void)setNumberOfLines:(NSInteger)numberOfLines
{
_numberOfLines = numberOfLines;
[self reloadAllComponents];
[self setNeedsLayout];
}

- (void) setFont:(UIFont *)font
{
_font = font;
[self reloadAllComponents];
[self setNeedsLayout];
}

#pragma mark - UIPickerViewDataSource protocol

- (NSInteger)numberOfComponentsInPickerView:(__unused UIPickerView *)pickerView
Expand All @@ -70,33 +85,44 @@ - (NSString *)pickerView:(__unused UIPickerView *)pickerView
return [RCTConvert NSString:_items[row][@"label"]];
}

- (CGFloat)pickerView:(__unused UIPickerView *)pickerView rowHeightForComponent:(NSInteger)__unused component {
return _font.pointSize + 19;
- (CGFloat)pickerView:(__unused UIPickerView *)pickerView rowHeightForComponent:(__unused NSInteger) component {
return (_font.lineHeight) * _numberOfLines + 20;
}

- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UILabel *)label
reusingView:(UIView *)view
{
if (!label) {
label = [[UILabel alloc] initWithFrame:(CGRect){
CGPointZero,
{
[pickerView rowSizeForComponent:component].width,
[pickerView rowSizeForComponent:component].height,
}
}];
if (!view) {
CGFloat rowHeight = [pickerView rowSizeForComponent:component].height;
CGFloat rowWidth = [pickerView rowSizeForComponent:component].width;
view = [[UIView alloc] initWithFrame:CGRectZero];
RNCPickerLabel* label = [[RNCPickerLabel alloc] initWithFrame:(CGRect) {
CGPointZero,
{
rowWidth,
rowHeight,
}
}];
[view insertSubview:label atIndex:0];
}

RNCPickerLabel* label = view.subviews[0];
label.font = _font;

label.textColor = [RCTConvert UIColor:_items[row][@"textColor"]] ?: _color;

label.textAlignment = _textAlign;
label.text = [self pickerView:pickerView titleForRow:row forComponent:component];
label.accessibilityIdentifier = _items[row][@"testID"];
return label;

label.numberOfLines = _numberOfLines;

label.leftInset = 20.0;
label.rightInset = 20.0;

return view;
}

- (void)pickerView:(__unused UIPickerView *)pickerView
Expand Down
6 changes: 6 additions & 0 deletions ios/RNCPicker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
65A65136236317E000467FDE /* RNCPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 65A65135236317E000467FDE /* RNCPickerManager.m */; };
83CE2A3626889B7700470183 /* RNCPickerLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CE2A3526889B7700470183 /* RNCPickerLabel.m */; };
B3E7B58A1CC2AC0600A0062D /* RNCPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNCPicker.m */; };
/* End PBXBuildFile section */

Expand All @@ -27,6 +28,8 @@
134814201AA4EA6300B7C361 /* libRNCPicker.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCPicker.a; sourceTree = BUILT_PRODUCTS_DIR; };
65A65134236317E000467FDE /* RNCPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCPickerManager.h; sourceTree = "<group>"; };
65A65135236317E000467FDE /* RNCPickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCPickerManager.m; sourceTree = "<group>"; };
83CE2A3426889B7700470183 /* RNCPickerLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCPickerLabel.h; sourceTree = "<group>"; };
83CE2A3526889B7700470183 /* RNCPickerLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCPickerLabel.m; sourceTree = "<group>"; };
B3E7B5881CC2AC0600A0062D /* RNCPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCPicker.h; sourceTree = "<group>"; };
B3E7B5891CC2AC0600A0062D /* RNCPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCPicker.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand All @@ -53,6 +56,8 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
83CE2A3426889B7700470183 /* RNCPickerLabel.h */,
83CE2A3526889B7700470183 /* RNCPickerLabel.m */,
65A65134236317E000467FDE /* RNCPickerManager.h */,
65A65135236317E000467FDE /* RNCPickerManager.m */,
B3E7B5881CC2AC0600A0062D /* RNCPicker.h */,
Expand Down Expand Up @@ -118,6 +123,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
83CE2A3626889B7700470183 /* RNCPickerLabel.m in Sources */,
B3E7B58A1CC2AC0600A0062D /* RNCPicker.m in Sources */,
65A65136236317E000467FDE /* RNCPickerManager.m in Sources */,
);
Expand Down
10 changes: 10 additions & 0 deletions ios/RNCPickerLabel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>

@interface RNCPickerLabel : UILabel

@property (nonatomic, assign) CGFloat topInset;
@property (nonatomic, assign) CGFloat bottomInset;
@property (nonatomic, assign) CGFloat leftInset;
@property (nonatomic, assign) CGFloat rightInset;

@end
31 changes: 31 additions & 0 deletions ios/RNCPickerLabel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#import "RNCPickerLabel.h"

@implementation RNCPickerLabel

- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.topInset = 0.0;
self.bottomInset = 0.0;
self.leftInset = 0.0;
self.rightInset = 0.0;
}
return self;
}

- (void)drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = UIEdgeInsetsMake(self.topInset, self.leftInset, self.bottomInset, self.rightInset);
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

- (CGSize)intrinsicContentSize
{
CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize];
intrinsicSuperViewContentSize.height += self.topInset + self.bottomInset;
intrinsicSuperViewContentSize.width += self.leftInset + self.rightInset;
return intrinsicSuperViewContentSize;
}

@end
1 change: 1 addition & 0 deletions ios/RNCPickerManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
RCT_EXPORT_VIEW_PROPERTY(textAlign, NSTextAlignment)
RCT_EXPORT_VIEW_PROPERTY(numberOfLines, NSInteger)
RCT_CUSTOM_VIEW_PROPERTY(fontSize, NSNumber, RNCPicker)
{
view.font = [RCTFont updateFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
Expand Down
7 changes: 7 additions & 0 deletions js/PickerIOS.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type RNCPickerIOSType = HostComponent<
selectedIndex: number,
style?: ?TextStyleProp,
testID?: ?string,
numberOfLines?: ?number,
|}>,
>;

Expand All @@ -57,6 +58,7 @@ type Props = $ReadOnly<{|
onChange?: ?(event: PickerIOSChangeEvent) => mixed,
onValueChange?: ?(itemValue: string | number, itemIndex: number) => mixed,
selectedValue: ?(number | string),
numberOfLines: ?number,
|}>;

type State = {|
Expand Down Expand Up @@ -103,6 +105,10 @@ class PickerIOS extends React.Component<Props, State> {
}

render(): React.Node {
let numberOfLines = Math.round(this.props.numberOfLines ?? 1);
if (numberOfLines < 1) {
numberOfLines = 1;
}
return (
<View style={this.props.style}>
<RNCPickerNativeComponent
Expand All @@ -114,6 +120,7 @@ class PickerIOS extends React.Component<Props, State> {
items={this.state.items}
selectedIndex={this.state.selectedIndex}
onChange={this._onChange}
numberOfLines={numberOfLines}
/>
</View>
);
Expand Down
1 change: 1 addition & 0 deletions js/RNCPickerNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type RNCPickerIOSType = HostComponent<
selectedIndex: number,
style?: ?TextStyleProp,
testID?: ?string,
numberOfLines?: ?number,
|}>,
>;

Expand Down
4 changes: 2 additions & 2 deletions typings/Picker.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ export interface PickerProps<T = ItemValue> extends ViewProps {
*/
dropdownIconRippleColor?: number | ColorValue;
/**
* On Android, used to truncate the text with an ellipsis after computing the text layout, including line wrapping,
* On Android & iOS, used to truncate the text with an ellipsis after computing the text layout, including line wrapping,
* such that the total number of lines does not exceed this number. Default is '1'
* @platform android
* @platform android & iOS
*/
numberOfLines?: number;
/**
Expand Down
13 changes: 7 additions & 6 deletions typings/PickerIOS.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ export interface PickerIOSItemProps {
declare class PickerIOSItem extends React.Component<PickerIOSItemProps, {}> {}

export interface PickerIOSProps extends ViewProps {
itemStyle?: StyleProp<TextStyle>;
style?: StyleProp<TextStyle>;
onChange?: React.SyntheticEvent<{itemValue: ItemValue, itemIndex: number}>;
onValueChange?: (itemValue: ItemValue, itemIndex: number) => void;
selectedValue?: ItemValue;
testID?: string;
itemStyle?: StyleProp<TextStyle>;
style?: StyleProp<TextStyle>;
onChange?: React.SyntheticEvent<{itemValue: ItemValue, itemIndex: number}>;
onValueChange?: (itemValue: ItemValue, itemIndex: number) => void;
selectedValue?: ItemValue;
testID?: string;
numberOfLines?: number;
}

declare class PickerIOS extends React.Component<PickerIOSProps, {}> {
Expand Down

0 comments on commit 3fdddb6

Please sign in to comment.