Skip to content

Commit

Permalink
[ios] Add vendored @react-native-community/segmented-control (#8038)
Browse files Browse the repository at this point in the history
  • Loading branch information
marchenk0va committed May 22, 2020
1 parent 359380d commit 75490e9
Show file tree
Hide file tree
Showing 13 changed files with 693 additions and 1 deletion.
1 change: 1 addition & 0 deletions apps/bare-expo/package.json
Expand Up @@ -79,6 +79,7 @@
},
"dependencies": {
"@babel/runtime": "^7.5.5",
"@react-native-community/segmented-control": "^1.4.0",
"@react-navigation/web": "2.0.0-alpha.0",
"expo": "~37.0.6",
"expo-image": "~1.0.0-alpha.0",
Expand Down
1 change: 1 addition & 0 deletions apps/native-component-list/package.json
Expand Up @@ -16,6 +16,7 @@
"@react-native-community/datetimepicker": "2.2.2",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/netinfo": "5.5.0",
"@react-native-community/segmented-control": "^1.4.0",
"@react-native-community/viewpager": "3.3.0",
"@react-navigation/web": "2.0.0-alpha.0",
"date-format": "^2.0.0",
Expand Down
2 changes: 2 additions & 0 deletions apps/native-component-list/src/navigation/ExpoComponents.ts
Expand Up @@ -36,6 +36,7 @@ const ReanimatedImagePreview = optionalRequire(() =>
const ReanimatedProgress = optionalRequire(() =>
require('../screens/Reanimated/ReanimatedProgressScreen')
);
const SegmentedControl = optionalRequire(() => require('../screens/SegmentedControlScreen'));
const SVGExample = optionalRequire(() => require('../screens/SVG/SVGExampleScreen'));
const SVG = optionalRequire(() => require('../screens/SVG/SVGScreen'));
const SharedElement = optionalRequire(() => require('../screens/SharedElementScreen'));
Expand Down Expand Up @@ -67,6 +68,7 @@ const optionalScreens: { [key: string]: React.ComponentType | null } = {
ReanimatedProgress,
Gif,
FacebookAds,
SegmentedControl,
SVG,
SVGExample,
LinearGradient,
Expand Down
Expand Up @@ -36,6 +36,7 @@ export default class ExpoComponentsScreen extends React.Component {
'MaskedView',
'ReanimatedImagePreview',
'ReanimatedProgress',
'SegmentedControl',
'Screens',
'SharedElement',
'SVG',
Expand Down
104 changes: 104 additions & 0 deletions apps/native-component-list/src/screens/SegmentedControlScreen.tsx
@@ -0,0 +1,104 @@
import SegmentedControl from '@react-native-community/segmented-control';
import React, { useState } from 'react';
import { StyleSheet, ScrollView, Text, View } from 'react-native';

// This example is a copy from https://github.com/react-native-community/segmented-control/blob/master/example

const SegmentedControlScreen = () => {
const [values] = useState(['One', 'Two', 'Three']);
const [value, setValue] = useState('Unselected');
const [selectedIndex, setIndex] = useState(undefined);

const _onChange = event => {
setIndex(event.nativeEvent.selectedSegmentIndex);
};

const _onValueChange = (value: string) => {
setValue(value);
};

return (
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.segmentContainer}>
<Text style={styles.text}>Segmented controls can have values</Text>
<SegmentedControl values={['One', 'Two']} />
</View>

<View style={styles.segmentSection}>
<SegmentedControl values={['One', 'Two', 'Three', 'Four', 'Five']} />
</View>

<View style={styles.segmentSection}>
<Text style={styles.text}>Segmented controls can have pre-selected values</Text>
<SegmentedControl values={['One', 'Two']} selectedIndex={0} />
</View>

<View style={styles.segmentSection}>
<Text style={styles.text}>Segmented controls can be momentary</Text>
<SegmentedControl values={['One', 'Two']} momentary />
</View>

<View style={styles.segmentSection}>
<Text style={styles.text}>Segmented controls can be disabled</Text>
<SegmentedControl enabled={false} values={['One', 'Two']} selectedIndex={1} />
</View>

<View style={styles.segmentContainer}>
<Text style={styles.text}>Custom colors can be provided</Text>
<SegmentedControl
tintColor="#ff0000"
values={['One', 'Two', 'Three', 'Four']}
selectedIndex={0}
backgroundColor="#0000ff"
activeTextColor="white"
/>
</View>
<View style={styles.segmentContainer}>
<SegmentedControl
tintColor="#00ff00"
values={['One', 'Two', 'Three']}
selectedIndex={1}
activeTextColor="black"
/>
</View>
<View style={styles.segmentSection}>
<SegmentedControl textColor="#ff00ff" values={['One', 'Two']} selectedIndex={1} />
</View>

<View>
<Text style={styles.text}>Custom colors can be provided</Text>
<View style={styles.segmentContainer}>
<SegmentedControl
values={values}
selectedIndex={selectedIndex}
onChange={_onChange}
onValueChange={_onValueChange}
/>
</View>
<Text style={[styles.text]}>
Value: {value} Index: {selectedIndex}
</Text>
</View>
</ScrollView>
);
};

const styles = StyleSheet.create({
text: {
fontSize: 14,
textAlign: 'center',
fontWeight: '500',
margin: 10,
},
segmentContainer: {
marginBottom: 10,
},
segmentSection: {
marginBottom: 25,
},
container: {
paddingTop: 80,
},
});

export default SegmentedControlScreen;
1 change: 1 addition & 0 deletions docs/common/navigation.js
Expand Up @@ -195,6 +195,7 @@ const sections = [
'SafeAreaView',
'ScrollView',
'SectionList',
'SegmentedControl',
'SegmentedControlIOS',
'Slider',
'SnapshotViewIOS',
Expand Down
@@ -0,0 +1,17 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>

#import <React/RCTComponent.h>

@interface RNCSegmentedControl : UISegmentedControl

@property (nonatomic, assign) NSInteger selectedIndex;
@property (nonatomic, copy) RCTBubblingEventBlock onChange;

@end
@@ -0,0 +1,111 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RNCSegmentedControl.h"

#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/UIView+React.h>

@implementation RNCSegmentedControl

- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
_selectedIndex = self.selectedSegmentIndex;
[self addTarget:self action:@selector(didChange)
forControlEvents:UIControlEventValueChanged];
}
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)setSelectedIndex:(NSInteger)selectedIndex
{
_selectedIndex = selectedIndex;
super.selectedSegmentIndex = selectedIndex;
}

- (void)setBackgroundColor:(UIColor *)backgroundColor
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
[super setBackgroundColor:backgroundColor];
}
#endif
}

- (void)setTextColor:(UIColor *)textColor
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
[self setTitleTextAttributes:@{NSForegroundColorAttributeName: textColor}
forState:UIControlStateNormal];
}
#endif
}

- (void)setActiveTextColor:(UIColor *)textColor
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
[self setTitleTextAttributes:@{NSForegroundColorAttributeName: textColor}
forState:UIControlStateSelected];
}
#endif
}

- (void)setTintColor:(UIColor *)tintColor
{
[super setTintColor:tintColor];
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
[self setSelectedSegmentTintColor:tintColor];
[self setTitleTextAttributes:@{NSForegroundColorAttributeName: tintColor}
forState:UIControlStateNormal];
}
#endif
}

- (void)didChange
{
_selectedIndex = self.selectedSegmentIndex;
if (_onChange) {
_onChange(@{
@"value": [self titleForSegmentAtIndex:_selectedIndex],
@"selectedSegmentIndex": @(_selectedIndex)
});
}
}

- (void)setAppearance:(NSString *)appearanceString
{
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available(iOS 13.0, *)) {
if ([appearanceString isEqual: @"dark"]) {
[self setOverrideUserInterfaceStyle:UIUserInterfaceStyleDark];
} else if ([appearanceString isEqual: @"light"]) {
[self setOverrideUserInterfaceStyle:UIUserInterfaceStyleLight];
}
}
#endif
}

@end
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <React/RCTViewManager.h>

@interface RNCSegmentedControlManager : RCTViewManager

@end
@@ -0,0 +1,34 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RNCSegmentedControlManager.h"

#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import "RNCSegmentedControl.h"

@implementation RNCSegmentedControlManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
return [RNCSegmentedControl new];
}

RCT_EXPORT_VIEW_PROPERTY(values, NSArray<NSString *>)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(textColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(activeTextColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(momentary, BOOL)
RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(appearance, NSString)

@end
1 change: 1 addition & 0 deletions packages/expo/bundledNativeModules.json
Expand Up @@ -90,6 +90,7 @@
"@react-native-community/datetimepicker": "2.2.2",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/viewpager": "3.3.0",
"@react-native-community/segmented-control": "1.4.0",
"expo-error-recovery": "~1.1.0",
"expo-module-template": "~8.2.0",
"expo-image-loader": "~1.0.1",
Expand Down
10 changes: 10 additions & 0 deletions tools/expotools/src/commands/UpdateVendoredModule.ts
Expand Up @@ -333,6 +333,16 @@ const vendoredModulesConfig: { [key: string]: VendoredModuleConfig } = {
},
],
},
'@react-native-community/segmented-control': {
repoUrl: 'https://github.com/react-native-community/segmented-control',
installableInManagedApps: true,
steps: [
{
sourceIosPath: 'ios',
targetIosPath: 'Api/Components/SegmentedControl',
},
],
},
};

async function getBundledNativeModulesAsync(): Promise<{ [key: string]: string }> {
Expand Down

0 comments on commit 75490e9

Please sign in to comment.