1/** 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 */ 7 8#import "RNCPicker.h" 9 10#import <React/RCTConvert.h> 11#import <React/RCTUtils.h> 12 13@interface RNCPicker() <UIPickerViewDataSource, UIPickerViewDelegate> 14@end 15 16@implementation RNCPicker 17 18- (instancetype)initWithFrame:(CGRect)frame 19{ 20 if ((self = [super initWithFrame:frame])) { 21 _color = [UIColor blackColor]; 22 _font = [UIFont systemFontOfSize:21]; // TODO: selected title default should be 23.5 23 _numberOfLines = 1; 24 _selectedIndex = NSNotFound; 25 _selectionColor = 0; 26 _textAlign = NSTextAlignmentCenter; 27 self.delegate = self; 28 self.dataSource = self; 29 [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) 30 } 31 return self; 32} 33 34RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) 35 36- (void)setItems:(NSArray<NSDictionary *> *)items 37{ 38 _items = [items copy]; 39 [self setNeedsLayout]; 40} 41 42- (void)setSelectedIndex:(NSInteger)selectedIndex 43{ 44 if (_selectedIndex != selectedIndex) { 45 BOOL animated = _selectedIndex != NSNotFound; // Don't animate the initial value 46 _selectedIndex = selectedIndex; 47 dispatch_async(dispatch_get_main_queue(), ^{ 48 [self selectRow:selectedIndex inComponent:0 animated:animated]; 49 }); 50 } 51} 52 53- (void)setNumberOfLines:(NSInteger)numberOfLines 54{ 55 _numberOfLines = numberOfLines; 56 [self reloadAllComponents]; 57 [self setNeedsLayout]; 58} 59 60- (void) setFont:(UIFont *)font 61{ 62 _font = font; 63 [self reloadAllComponents]; 64 [self setNeedsLayout]; 65} 66 67#pragma mark - UIPickerViewDataSource protocol 68 69- (NSInteger)numberOfComponentsInPickerView:(__unused UIPickerView *)pickerView 70{ 71 return 1; 72} 73 74- (NSInteger)pickerView:(__unused UIPickerView *)pickerView 75numberOfRowsInComponent:(__unused NSInteger)component 76{ 77 return _items.count; 78} 79 80#pragma mark - UIPickerViewDelegate methods 81 82- (NSString *)pickerView:(__unused UIPickerView *)pickerView 83 titleForRow:(NSInteger)row 84 forComponent:(__unused NSInteger)component 85{ 86 return [RCTConvert NSString:_items[row][@"label"]]; 87} 88 89- (CGFloat)pickerView:(__unused UIPickerView *)pickerView rowHeightForComponent:(__unused NSInteger) component { 90 return (_font.lineHeight) * _numberOfLines + 20; 91} 92 93- (UIView *)pickerView:(UIPickerView *)pickerView 94 viewForRow:(NSInteger)row 95 forComponent:(NSInteger)component 96 reusingView:(UIView *)view 97{ 98 if (!view) { 99 CGFloat rowHeight = [pickerView rowSizeForComponent:component].height; 100 CGFloat rowWidth = [pickerView rowSizeForComponent:component].width; 101 view = [[UIView alloc] initWithFrame:CGRectZero]; 102 RNCPickerLabel* label = [[RNCPickerLabel alloc] initWithFrame:(CGRect) { 103 CGPointZero, 104 { 105 rowWidth, 106 rowHeight, 107 } 108 }]; 109 [view insertSubview:label atIndex:0]; 110 } 111 112 if (@available(iOS 14.0, *)) { 113 if (_selectionColor) { 114 pickerView.subviews[1].backgroundColor = [RCTConvert UIColor:@(_selectionColor)]; 115 } 116 } 117 118 RNCPickerLabel* label = view.subviews[0]; 119 label.font = _font; 120 121 label.textColor = [RCTConvert UIColor:_items[row][@"textColor"]] ?: _color; 122 123 label.textAlignment = _textAlign; 124 label.text = [self pickerView:pickerView titleForRow:row forComponent:component]; 125 label.accessibilityIdentifier = _items[row][@"testID"]; 126 127 label.numberOfLines = _numberOfLines; 128 129 label.leftInset = 20.0; 130 label.rightInset = 20.0; 131 132 return view; 133} 134 135- (void)pickerView:(__unused UIPickerView *)pickerView 136 didSelectRow:(NSInteger)row inComponent:(__unused NSInteger)component 137{ 138 _selectedIndex = row; 139 if (_onChange && _items.count > (NSUInteger)row) { 140 _onChange(@{ 141 @"newIndex": @(row), 142 @"newValue": RCTNullIfNil(_items[row][@"value"]), 143 }); 144 } 145} 146 147@end 148