Skip to content

Commit

Permalink
feat: add column width prop
Browse files Browse the repository at this point in the history
  • Loading branch information
Liam committed Jul 16, 2022
1 parent bae2d88 commit 61462fc
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 22 deletions.
1 change: 1 addition & 0 deletions ios/Picky.h
Expand Up @@ -15,6 +15,7 @@
@interface Picky : UIPickerView

@property (nonatomic, copy) NSArray *data;
@property (nonatomic, copy) NSArray *columnWidths;
@property (nonatomic, copy) NSArray *selectedIndexes;

@property (nonatomic, assign) BOOL loop;
Expand Down
24 changes: 21 additions & 3 deletions ios/Picky.m
Expand Up @@ -25,6 +25,7 @@ - (instancetype)initWithFrame:(CGRect)frame
_numberOfLines = 1;
_loop = false;
_loopThreshold = 1;
_columnWidths = [NSArray new];
_selectedIndexes = [NSArray new];

self.delegate = self;
Expand All @@ -46,6 +47,13 @@ - (void)setData:(NSArray *)data
[self setNeedsLayout];
}

- (void)setColumnWidths:(NSArray *)columnWidths
{
_columnWidths = [columnWidths copy];

[self setNeedsLayout];
}

- (void)setSelectedIndexes:(NSArray *)selectedIndexes
{
BOOL animated = [_selectedIndexes count] > 0; // Don't animate the initial value
Expand Down Expand Up @@ -90,7 +98,7 @@ - (void)setNumberOfLines:(NSInteger)numberOfLines
[self setNeedsLayout];
}

- (void) setFont:(UIFont *)font
- (void)setFont:(UIFont *)font
{
_font = font;
[self reloadAllComponents];
Expand Down Expand Up @@ -128,7 +136,7 @@ - (NSInteger)numberOfComponentsInPickerView:(__unused UIPickerView *)pickerView
- (NSInteger)pickerView:(__unused UIPickerView *)pickerView
numberOfRowsInComponent:(__unused NSInteger)component
{
return [[_data objectAtIndex: component] count] * _loopThreshold;
return [[_data objectAtIndex:component] count] * _loopThreshold;
}

#pragma mark - UIPickerViewDelegate methods
Expand All @@ -140,10 +148,20 @@ - (NSString *)pickerView:(__unused UIPickerView *)pickerView
return [RCTConvert NSString: [self dataForRow:row inComponent:component][@"label"]];
}

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

- (CGFloat)pickerView:(__unused UIPickerView *)pickerView
widthForComponent:(__unused NSInteger)component {
if ([_columnWidths count] == 0) {
return 0;
}

return [[_columnWidths objectAtIndex:component] floatValue];
}

- (UIView *)pickerView:(UIPickerView *)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
Expand Down
2 changes: 2 additions & 0 deletions ios/PickyManager.m
Expand Up @@ -23,6 +23,8 @@ - (UIView *)view

RCT_EXPORT_VIEW_PROPERTY(data, NSArray)

RCT_EXPORT_VIEW_PROPERTY(columnWidths, NSNumberArray)

RCT_EXPORT_VIEW_PROPERTY(selectedIndexes, NSNumberArray)

RCT_EXPORT_VIEW_PROPERTY(loop, BOOL)
Expand Down
1 change: 1 addition & 0 deletions src/NativePicker.tsx
Expand Up @@ -18,6 +18,7 @@ type NativeCommonProps = {

type NativeIOSProps = {
numberOfLines?: number;
columnWidths: number[];
style?: StyleProp<ViewStyle>;
selectedIndexes?: number[];
testID?: string;
Expand Down
95 changes: 76 additions & 19 deletions src/Picker.tsx
@@ -1,11 +1,19 @@
import React, { Children, ReactElement, useCallback, useMemo } from 'react';
import React, {
Children,
ReactElement,
useCallback,
useMemo,
useState,
} from 'react';
import {
StyleSheet,
Platform,
processColor,
View,
StyleProp,
ViewStyle,
useWindowDimensions,
LayoutChangeEvent,
} from 'react-native';
import { NativePicker } from './NativePicker';
import type { PickerColumnProps } from './PickerColumn';
Expand Down Expand Up @@ -51,9 +59,12 @@ export const Picker = ({
children,
testID,
}: PickerProps) => {
const { data, selectedIndexes } = useNativePickerColumns({
const { width: windowWidth } = useWindowDimensions();
const [viewWidth, setViewWidth] = useState(windowWidth);
const { data, columnWidths, selectedIndexes } = useNativePickerColumns({
children,
textColor,
viewWidth,
});

const handleOnChange: NativeOnChange = useCallback(
Expand All @@ -71,27 +82,44 @@ export const Picker = ({
[onChange, children]
);

const handleOnLayout = useCallback(
({
nativeEvent: {
layout: { width },
},
}: LayoutChangeEvent) => setViewWidth(width),
[]
);

if (Platform.OS === 'ios') {
return (
<NativePicker
selectedIndexes={selectedIndexes}
onChange={handleOnChange}
numberOfLines={numberOfLines}
data={data}
loop={loop}
style={[styles.picker, style]}
testID={testID}
/>
<View onLayout={handleOnLayout}>
<NativePicker
selectedIndexes={selectedIndexes}
onChange={handleOnChange}
numberOfLines={numberOfLines}
data={data}
columnWidths={columnWidths}
loop={loop}
style={[styles.picker, style]}
testID={testID}
/>
</View>
);
}

if (Platform.OS === 'android') {
return (
<View style={styles.androidContainer}>
<View onLayout={handleOnLayout} style={styles.androidContainer}>
{data.map((componentData, index) => (
<View
key={`picky-component-${index}`}
style={[styles.androidPickyContainer, style]}
style={[
{
width: columnWidths[index] + LABEL_INSET_SPACE,
},
style,
]}
>
<NativePicker
column={index}
Expand Down Expand Up @@ -120,13 +148,19 @@ export const Picker = ({
};

const useNativePickerColumns = ({
viewWidth,
children,
textColor,
}: Required<Pick<PickerProps, 'children' | 'textColor'>>) =>
}: Required<Pick<PickerProps, 'children' | 'textColor'>> & {
viewWidth: number;
}) =>
useMemo(() => {
let columnWidths: number[] = [];
const selectedIndexes: number[] = [];
const data: NativePickerDataItem[] = [];

let availableSpace = viewWidth;

Children.forEach(children, (columnChild, columnChildIndex) => {
const columnItems: NativeItem[] = [];

Expand Down Expand Up @@ -154,18 +188,41 @@ const useNativePickerColumns = ({
selectedIndexes.push(0);
}

if (typeof columnChild.props.width === 'number') {
const w = Math.max(columnChild.props.width - LABEL_INSET_SPACE, 0);

availableSpace -= columnChild.props.width;

columnWidths.push(w);
} else {
columnWidths.push(-1);
}

data.push(columnItems);
});

return { data, selectedIndexes };
}, [children, textColor]);
// Automatically set width for remaining columns to the available space
const columnsWithoutWidth = columnWidths.filter((w) => w < 0);
if (columnsWithoutWidth.length) {
columnWidths = columnWidths.map((w) =>
w < 0
? Math.max(
availableSpace / columnsWithoutWidth.length - LABEL_INSET_SPACE,
0
)
: w
);
}

return { data, columnWidths, selectedIndexes };
}, [children, textColor, viewWidth]);

const LABEL_INSET_SPACE = 20;

const styles = StyleSheet.create({
androidContainer: {
flexDirection: 'row',
},
androidPickyContainer: {
flex: 1,
width: '100%',
},
picker: {
height: 216,
Expand Down
1 change: 1 addition & 0 deletions src/PickerColumn.tsx
Expand Up @@ -5,6 +5,7 @@ import type { PickerColumnChangeItem } from './types';
type PickerColumnChild = ReactElement<PickerItemProps>;

export interface PickerColumnProps {
width?: number;
selectedValue?: string | number;
onChange?: (item: PickerColumnChangeItem) => void;
children: PickerColumnChild | PickerColumnChild[];
Expand Down

0 comments on commit 61462fc

Please sign in to comment.