Skip to content
Binary file added example/assets/images/user.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/images/user@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/images/user@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 16 additions & 3 deletions example/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,24 @@ export default class App extends React.Component<{}, $FlowFixMeState> {
return (
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.segmentContainer}>
<Text style={styles.text}>Segmented controls can have values</Text>
<SegmentedControl values={['One', 'Two']} />
<Text style={styles.text}>
Segmented controls can have values and images
</Text>
<SegmentedControl
values={['One', 'Two', require('../assets/images/user.png')]}
/>
</View>
<View style={styles.segmentSection}>
<SegmentedControl values={['One', 'Two', 'Three', 'Four', 'Five']} />
<SegmentedControl
values={[
'One',
'Two',
require('../assets/images/user.png'),
'Three',
'Four',
'Five',
]}
/>
</View>
<View style={styles.segmentSection}>
<Text style={styles.text}>
Expand Down
26 changes: 17 additions & 9 deletions ios/RNCSegmentedControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@ - (instancetype)initWithFrame:(CGRect)frame {
return self;
}

- (void)setValues:(NSArray<NSString *> *)values {
[self removeAllSegments];
for (NSString *value in values) {
[self insertSegmentWithTitle:value
atIndex:self.numberOfSegments
animated:NO];
}
super.selectedSegmentIndex = _selectedIndex;
- (void)setValues:(NSArray *)values {
[self removeAllSegments];
for (id segment in values) {
if ([segment isKindOfClass:[NSMutableDictionary class]]){
UIImage *image = [[RCTConvert UIImage:segment] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
[self insertSegmentWithImage:image
atIndex:self.numberOfSegments
animated:NO];
} else {
[self insertSegmentWithTitle:(NSString *)segment
atIndex:self.numberOfSegments
animated:NO];
}
}
super.selectedSegmentIndex = _selectedIndex;
}

- (void)setSelectedIndex:(NSInteger)selectedIndex {
Expand Down Expand Up @@ -69,8 +76,9 @@ - (void)setTintColor:(UIColor *)tintColor {
- (void)didChange {
_selectedIndex = self.selectedSegmentIndex;
if (_onChange) {
NSString *segmentTitle = [self titleForSegmentAtIndex:_selectedIndex];
_onChange(@{
@"value" : [self titleForSegmentAtIndex:_selectedIndex],
@"value" : (segmentTitle) ? segmentTitle : [self imageForSegmentAtIndex:_selectedIndex],
@"selectedSegmentIndex" : @(_selectedIndex)
});
}
Expand Down
2 changes: 1 addition & 1 deletion ios/RNCSegmentedControlManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ - (UIView *)view {
return [RNCSegmentedControl new];
}

RCT_EXPORT_VIEW_PROPERTY(values, NSArray<NSString *>)
RCT_EXPORT_VIEW_PROPERTY(values, NSArray)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
Expand Down
13 changes: 11 additions & 2 deletions js/SegmentedControl.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

import * as React from 'react';
import {StyleSheet, processColor} from 'react-native';
import {StyleSheet, Image, processColor} from 'react-native';

import RNCSegmentedControlNativeComponent from './RNCSegmentedControlNativeComponent';
import type {Event, SegmentedControlProps} from './types';
Expand Down Expand Up @@ -54,7 +54,13 @@ class SegmentedControlIOS extends React.Component<Props> {
};

render() {
const {forwardedRef, fontStyle, activeFontStyle, ...props} = this.props;
const {
forwardedRef,
fontStyle,
activeFontStyle,
values,
...props
} = this.props;
return (
<RNCSegmentedControlNativeComponent
fontStyle={
Expand All @@ -79,6 +85,9 @@ class SegmentedControlIOS extends React.Component<Props> {
}
: undefined
}
values={values.map((val) =>
typeof val === 'string' ? val : Image.resolveAssetSource(val),
)}
{...props}
ref={forwardedRef}
style={[styles.segmentedControl, this.props.style]}
Expand Down
22 changes: 19 additions & 3 deletions js/SegmentedControlTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
'use strict';

import * as React from 'react';
import {StyleSheet, View, Text, TouchableOpacity} from 'react-native';
import {StyleSheet, View, Text, Image, TouchableOpacity} from 'react-native';
import type {FontStyle} from './types';

type Props = $ReadOnly<{|
value: string,
value: string | number | Object,
tintColor?: ?string,
onSelect: () => void,
selected: boolean,
Expand All @@ -18,6 +18,11 @@ type Props = $ReadOnly<{|
activeFontStyle?: FontStyle,
|}>;

function isBase64(str) {
const regex = /^data:image\/(?:gif|png|jpeg|bmp|webp)(?:;charset=utf-8)?;base64,(?:[A-Za-z0-9]|[+/])+={0,2}/;
return str && regex.test(str);
}

export const SegmentedControlTab = ({
onSelect,
value,
Expand Down Expand Up @@ -64,7 +69,13 @@ export const SegmentedControlTab = ({
disabled={!enabled}
onPress={onSelect}>
<View style={[styles.default]}>
<Text style={[idleStyle, selected && activeStyle]}>{value}</Text>
{typeof value === 'number' || typeof value === 'object' ? (
<Image source={value} style={styles.segmentImage} />
) : isBase64(value) ? (
<Image source={{uri: value}} style={styles.segmentImage} />
) : (
<Text style={[idleStyle, selected && activeStyle]}>{value}</Text>
)}
</View>
</TouchableOpacity>
);
Expand All @@ -82,4 +93,9 @@ const styles = StyleSheet.create({
activeText: {
fontWeight: '700',
},
segmentImage: {
width: 17,
height: 17,
resizeMode: 'contain',
},
});
4 changes: 2 additions & 2 deletions js/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type SegmentedControlProps = $ReadOnly<{|
/**
* The labels for the control's segment buttons, in order.
*/
values: $ReadOnlyArray<string>,
values: $ReadOnlyArray<string | number | Object>,
/**
* The index in `props.values` of the segment to be (pre)selected.
*/
Expand All @@ -42,7 +42,7 @@ export type SegmentedControlProps = $ReadOnly<{|
* Callback that is called when the user taps a segment;
* passes the segment's value as an argument
*/
onValueChange?: ?(value: string) => mixed,
onValueChange?: ?(value: string | number | Object) => mixed,
/**
* Callback that is called when the user taps a segment;
* passes the event as an argument
Expand Down