├── .gitignore
├── art
├── segment_1.png
└── segment_2.png
├── src
└── main
│ ├── res
│ ├── values
│ │ └── strings.xml
│ └── layout
│ │ └── radio_button.xml
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── higo
│ └── zhangyp
│ └── segmented
│ ├── AndroidSegmentedPackage.java
│ ├── AndroidSegmentedEvent.java
│ ├── AndroidSegmented.java
│ └── AndroidSegmentedManager.java
├── package.json
├── proguard-rules.pro
├── AndroidSegmented.js
├── README.md
└── react-native-segmented-android.iml
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/art/segment_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzyyppqq/react-native-segmented-android/HEAD/art/segment_1.png
--------------------------------------------------------------------------------
/art/segment_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzyyppqq/react-native-segmented-android/HEAD/art/segment_2.png
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | react-native-segmented-android
3 |
4 |
--------------------------------------------------------------------------------
/src/main/res/layout/radio_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-segmented-android",
3 | "version": "1.0.4",
4 | "description": "a high imitation of iOS segmented Controls",
5 | "main": "AndroidSegmented.js",
6 | "scripts": {
7 | "test": "react-native start"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/zzyyppqq/react-native-segmented-android.git"
12 | },
13 | "keywords": [
14 | "android",
15 | "segmented",
16 | "react-component",
17 | "react-native"
18 | ],
19 | "author": "zzyyppqq",
20 | "license": "ISC",
21 | "peerDependencies": {
22 | "react-native": ">= 0.18.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/zhangyipeng/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/src/main/java/com/higo/zhangyp/segmented/AndroidSegmentedPackage.java:
--------------------------------------------------------------------------------
1 | package com.higo.zhangyp.segmented;
2 |
3 |
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.bridge.JavaScriptModule;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.uimanager.ViewManager;
9 |
10 | import java.util.Arrays;
11 | import java.util.Collections;
12 | import java.util.List;
13 |
14 |
15 | public class AndroidSegmentedPackage implements ReactPackage {
16 | @Override
17 | public List createNativeModules(ReactApplicationContext reactApplicationContext) {
18 | return Collections.emptyList();
19 | }
20 |
21 | @Override
22 | public List createViewManagers(ReactApplicationContext reactApplicationContext) {
23 | return Arrays.asList(
24 | new AndroidSegmentedManager());
25 | }
26 |
27 | @Override
28 | public List> createJSModules() {
29 | return Collections.emptyList();
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/AndroidSegmented.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react-native');
4 | var { requireNativeComponent, PropTypes, View } = React;
5 |
6 | var NativeAndroidSegmented = requireNativeComponent('AndroidSegmented', AndroidSegmented);
7 |
8 | class AndroidSegmented extends React.Component {
9 | constructor() {
10 | super();
11 | this._onChange = this._onChange.bind(this);
12 | }
13 |
14 | _onChange(event) {
15 | if (this.props.onChange) {
16 | this.props.onChange(event.nativeEvent);
17 | }
18 | }
19 |
20 | render() {
21 | return (
22 |
25 | );
26 | }
27 | }
28 |
29 | var colorType = function (props, propName, componentName) {
30 | var checker = function() {
31 | var color = props[propName];
32 | var regex = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
33 | if (!regex.test(color)) {
34 | return new Error('Only accept color formats: #RRGGBB and #AARRGGBB');
35 | }
36 | };
37 |
38 | return PropTypes.string(props, propName, componentName) || checker();
39 | }
40 |
41 | AndroidSegmented.propTypes = {
42 | ...View.propTypes,
43 | childText: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.string ])),
44 | orientation:PropTypes.string,
45 | tintColor:PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.string ])),
46 | selectedPosition:PropTypes.number,
47 | onChange: PropTypes.func,
48 | }
49 |
50 | AndroidSegmented.defaultProps = {
51 |
52 | };
53 |
54 | module.exports = AndroidSegmented;
--------------------------------------------------------------------------------
/src/main/java/com/higo/zhangyp/segmented/AndroidSegmentedEvent.java:
--------------------------------------------------------------------------------
1 | package com.higo.zhangyp.segmented;
2 |
3 | import android.util.Log;
4 |
5 | import com.facebook.react.bridge.Arguments;
6 | import com.facebook.react.bridge.WritableMap;
7 | import com.facebook.react.uimanager.events.Event;
8 | import com.facebook.react.uimanager.events.RCTEventEmitter;
9 |
10 | /**
11 | * Created by zhangyipeng on 15/12/15.
12 | */
13 | public class AndroidSegmentedEvent extends Event {
14 |
15 | public static final String EVENT_NAME = "topChange";
16 | private final int selectedPosition;
17 |
18 | public AndroidSegmentedEvent(int viewId, long timestampMs, int selectedPosition) {
19 | super(viewId, timestampMs);
20 | this.selectedPosition = selectedPosition;
21 | }
22 |
23 |
24 | @Override
25 | public String getEventName() {
26 | return EVENT_NAME;
27 | }
28 |
29 | @Override
30 | public void dispatch(RCTEventEmitter rctEventEmitter) {
31 | rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
32 |
33 | }
34 |
35 |
36 | @Override
37 | public short getCoalescingKey() {
38 | return 0;
39 | }
40 |
41 | private WritableMap serializeEventData() {
42 | WritableMap eventData = Arguments.createMap();
43 | // eventData.putInt("target", getViewTag());
44 | eventData.putInt("selected", getPosition());
45 | Log.e("AAA","position="+getPosition());
46 |
47 | return eventData;
48 | }
49 |
50 | private int getPosition() {
51 | return selectedPosition;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/higo/zhangyp/segmented/AndroidSegmented.java:
--------------------------------------------------------------------------------
1 | package com.higo.zhangyp.segmented;
2 |
3 | import android.view.Gravity;
4 | import android.view.ViewGroup;
5 | import android.widget.RadioGroup;
6 |
7 | import com.facebook.react.uimanager.ThemedReactContext;
8 |
9 | import info.hoang8f.android.segmented.SegmentedGroup;
10 |
11 | /**
12 | * Created by zhangyipeng on 15/12/15.
13 | */
14 | public class AndroidSegmented extends SegmentedGroup{
15 |
16 |
17 | public void setSegmentOrientation(String str){
18 | if(str.equals("horizontal")){
19 | setOrientation(RadioGroup.HORIZONTAL);
20 | }else if(str.equals("vertical")){
21 | setOrientation(RadioGroup.VERTICAL);
22 | }
23 | }
24 |
25 |
26 | public AndroidSegmented(ThemedReactContext context) {
27 | super(context);
28 | setGravity(Gravity.CENTER);
29 |
30 | setLayoutParams(new ViewGroup.LayoutParams(
31 | ViewGroup.LayoutParams.WRAP_CONTENT,
32 | ViewGroup.LayoutParams.WRAP_CONTENT
33 | ));
34 | }
35 |
36 | private final Runnable mLayoutRunnable = new Runnable() {
37 | @Override
38 | public void run() {
39 | measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
40 | MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
41 | layout(getLeft(), getTop(), getRight(), getBottom());
42 | }
43 | };
44 |
45 | @Override
46 | public void requestLayout() {
47 | super.requestLayout();
48 | post(mLayoutRunnable);
49 | }
50 |
51 | @Override
52 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
53 | super.onLayout(changed, l, t, r, b);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-segmented-android
2 | a high imitation of iOS segmented Controls
3 |
4 | 
5 |
6 | ## Example
7 |
8 | ```js
9 | 'use strict';
10 |
11 | var React = require('react-native');
12 | var {
13 | AppRegistry,
14 | StyleSheet,
15 | Text,
16 | Dimensions,
17 | ToastAndroid,
18 | View,
19 | } = React;
20 |
21 | var AndroidSegmented = require('react-native-segmented-android');
22 | var deviceWidth = Dimensions.get('window').width;
23 | var deviceHeight = Dimensions.get('window').height;
24 |
25 | var ReactNativeSegmentedExample = React.createClass({
26 | onSelectPosition:function(event){
27 | console.log(event);
28 | ToastAndroid.show('segment '+event.selected, ToastAndroid.SHORT)
29 | },
30 | render: function() {
31 | return (
32 |
33 |
42 |
43 |
52 |
53 | );
54 | }
55 | });
56 |
57 | ```
58 |
59 | ## Install
60 |
61 | ### Step 1 - Install the npm package
62 |
63 | ```sh
64 | $ npm install react-native-segmented-android --save
65 | ```
66 |
67 | ### Step 2 - Update Gradle Settings
68 |
69 | ```gradle
70 | // file: android/settings.gradle
71 | ...
72 |
73 | include ':react-native-segmented-android', ':app'
74 | project(':react-native-segmented-android').projectDir = new File(rootProject.projectDir,'../node_modules/react-native-segmented-android')
75 | ```
76 |
77 | ### Step 3 - Update app Gradle Build
78 |
79 | ```gradle
80 | // file: android/app/build.gradle
81 | ...
82 |
83 | dependencies {
84 | ...
85 | compile project(':react-native-segmented-android')
86 | }
87 | ```
88 |
89 | ### Step 4 - Register React Package
90 |
91 | ```java
92 | ...
93 | import com.higo.zhangyp.segmented.AndroidSegmentedPackage; // <-- import
94 |
95 | public class MainActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler {
96 |
97 | private ReactInstanceManager mReactInstanceManager;
98 | private ReactRootView mReactRootView;
99 |
100 | @Override
101 | protected void onCreate(Bundle savedInstanceState) {
102 | super.onCreate(savedInstanceState);
103 | mReactRootView = new ReactRootView(this);
104 | mReactInstanceManager = ReactInstanceManager.builder()
105 | .setApplication(getApplication())
106 | .setBundleAssetName("index.android.bundle")
107 | .setJSMainModuleName("index.android")
108 | .addPackage(new MainReactPackage())
109 | .addPackage(new AndroidSegmentedPackage()) // <-- Register package here
110 | .setUseDeveloperSupport(BuildConfig.DEBUG)
111 | .setInitialLifecycleState(LifecycleState.RESUMED)
112 | .build();
113 | mReactRootView.startReactApplication(mReactInstanceManager, "AwesomeProject", null);
114 | setContentView(mReactRootView);
115 | }
116 | ...
117 |
--------------------------------------------------------------------------------
/src/main/java/com/higo/zhangyp/segmented/AndroidSegmentedManager.java:
--------------------------------------------------------------------------------
1 | package com.higo.zhangyp.segmented;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.os.SystemClock;
6 | import android.view.LayoutInflater;
7 | import android.widget.RadioButton;
8 | import android.widget.RadioGroup;
9 |
10 | import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
11 | import com.facebook.react.bridge.ReadableArray;
12 | import com.facebook.react.uimanager.annotations.ReactProp;
13 | import com.facebook.react.uimanager.SimpleViewManager;
14 | import com.facebook.react.uimanager.ThemedReactContext;
15 | import com.facebook.react.uimanager.UIManagerModule;
16 |
17 | /**
18 | * Created by zhangyipeng on 15/12/15.
19 | */
20 | public class AndroidSegmentedManager extends SimpleViewManager {
21 |
22 | public static final String REACT_CLASS = "AndroidSegmented";
23 |
24 | private static final String COLOR_REGEX = "^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$";
25 |
26 | private Context context;
27 |
28 | @Override
29 | public String getName() {
30 | return REACT_CLASS;
31 | }
32 |
33 | @Override
34 | protected AndroidSegmented createViewInstance(ThemedReactContext reactContext) {
35 | this.context = reactContext;
36 | return new AndroidSegmented(reactContext);
37 | }
38 |
39 |
40 | @Override
41 | protected void addEventEmitters(final ThemedReactContext reactContext, final AndroidSegmented view) {
42 |
43 | view.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
44 | @Override
45 | public void onCheckedChanged(RadioGroup group, int checkedId) {
46 |
47 | int childCount = view.getChildCount();
48 | for (int i = 0; i < childCount; i++) {
49 | ((RadioButton)view.getChildAt(i)).setChecked(false);
50 | if (view.getChildAt(i).getId() == checkedId) {
51 | ((RadioButton)view.getChildAt(i)).setChecked(true);
52 |
53 |
54 | reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()
55 | .dispatchEvent(
56 | new AndroidSegmentedEvent(
57 | view.getId(),
58 | SystemClock.uptimeMillis(),
59 | i));
60 | }
61 | }
62 | }
63 | });
64 |
65 |
66 | }
67 |
68 |
69 | @ReactProp(name = "childText")
70 | public void setChildText(AndroidSegmented view, ReadableArray data) {
71 | int childCount = data.size();
72 |
73 | for (int i = 0; i < childCount; ++i) {
74 | RadioButton child = (RadioButton) LayoutInflater.from(context).inflate(R.layout.radio_button, null);
75 |
76 | child.setText(data.getString(i));
77 | view.addView(child);
78 |
79 |
80 | }
81 | }
82 |
83 |
84 | @ReactProp(name = "selectedPosition")
85 | public void setSelectedChild(AndroidSegmented view, int position) {
86 | RadioButton radioBt = (RadioButton) (view.getChildAt(position));
87 | radioBt.setChecked(true);
88 | }
89 |
90 |
91 | @ReactProp(name = "orientation")
92 | public void setOrientation(AndroidSegmented view, String orientation) {
93 | view.setSegmentOrientation(orientation);
94 | }
95 |
96 |
97 | @ReactProp(name = "tintColor")
98 | public void setTintColor(AndroidSegmented view, ReadableArray data) {
99 |
100 | String type0 = data.getType(0).name();
101 | String type1 = data.getType(1).name();
102 |
103 | if ("String".equals(type0) && "String".equals(type1)) {
104 | String color0 = data.getString(0);
105 | String color1 = data.getString(1);
106 | if (color0 != null && color1 != null) {
107 | if (color0.matches(COLOR_REGEX) && color1.matches(COLOR_REGEX)) {
108 |
109 | view.setTintColor(Color.parseColor(color0), Color.parseColor(color1));
110 | } else {
111 | throw new JSApplicationIllegalArgumentException("Invalid arrowColor property: " + color0);
112 | }
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/react-native-segmented-android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------