diff --git a/README.md b/README.md index 60875498f3fbb9bf435fee65e8b05fd96a595146..6aff348021a63c9f8daecf802efa10d7168f58ec 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,7 @@ [![npm version](https://img.shields.io/npm/v/react-native-picker.svg?style=flat-square)](https://www.npmjs.com/package/react-native-picker) dependency status -A Picker written in pure javascript for cross-platform support. - -It was most likely an example of how to build a cross-platform Picker Component use [react-native-picker-android](https://github.com/beefe/react-native-picker-android). - -###Warn -if 0.14.2 <= react-native <=0.24 `npm install react-native-picker@2.0.5 --save` -if 0.24 < react-native `npm install react-native-picker --save` +A Native Picker with high performance ####Demo @@ -23,21 +17,19 @@ if 0.24 < react-native `npm install react-native-picker --save` ###Documentation ####Props -- style style of picker, you can set width and height of picker in this prop -- pickerElevation elevation of picker (for issue https://github.com/beefe/react-native-picker/issues/27) -- pickerBtnText string, tool bar's confirm btn text -- pickerCancelBtnText string, tool bar's cancel ben text -- pickerBtnStyle textStylePropType, tool bar's btn style -- pickerToolBarStyle viewStylePropType, tool bar's style -- showDuration number, animation of picker -- showMask boolean, default to be false, cancel the picker by tapping in the rest of the screen support when setted to be true -- pickerTitle string, title of picker -- pickerTitleStyle textStylePropType, style of title -- pickerData array -- selectedValue any -- onPickerDone function -- onPickerCancel function -- onValueChange function +- pickerConfirmBtnText string, 确认按钮文字 +- pickerCancelBtnText string, 取消按钮文字 +- pickerTitleText string, 标题文字 +- pickerConfirmBtnColor ['255', '66', '00', 0.5], 确认按钮字体颜色 +- pickerCancelBtnColor ['255', '66', '00', 0.5], 取消按钮字体颜色 +- pickerTitleColor ['255', '66', '00', 0.5], 标题字体颜色 +- pickerToolBarBg ['255', '66', '00', 0.5], 工具栏背景颜色 +- pickerBg ['255', '66', '00', 0.5], picker背景颜色 +- pickerData 数组或对象,picker数据 +- selectedValue string,默认选中数据 +- onPickerConfirm function,确认按钮回调 +- onPickerCancel function,取消按钮回调 +- onPickerSelect function,滚轮滚动时回调 ####Methods - toggle show or hide picker, default to be hiden @@ -53,21 +45,37 @@ if 0.24 < react-native `npm install react-native-picker --save` npm install react-native-picker --save ``` -####Step 2 - import and use in project +####Step 2 - link + +``` + react-native link +``` + +####Step 3 - import and use in project ```javascript - import Picker from 'react-native-picker' + import Picker from 'react-native-picker'; + + let data = []; + for(var i=0;i<100;i++){ + data.push(i); + } + + Picker.init({ + pickerData: data, + selectedValue: [59], + onPickerConfirm: data => { + console.log(data); + }, + onPickerCancel: data => { + console.log(data); + }, + onPickerSelect: data => { + console.log(data); + } + }); + Picker.show(); - ``` ###Notice @@ -104,11 +112,9 @@ if 0.24 < react-native `npm install react-native-picker --save` ```javascript pickerData = { - { - a: [1,2,3,4], - b: [5,6,7,8], - ... - } + a: [1,2,3,4], + b: [5,6,7,8], + ... }; selectedValue = ['a', 2]; ``` diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..ddc34da669e9f9b8f880e36cb6eaa847ee9de44d --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.facebook.react:react-native:0.20.1' +} diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..dc79a7df8c2489bafaebb1896a349f4604498a81 --- /dev/null +++ b/android/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/heng/Desktop/android-sdk-macosx/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..005069de69bec4c504a75c0df69df0b35ae91eae --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/android/src/main/java/com/beefe/picker/PickerViewModule.java b/android/src/main/java/com/beefe/picker/PickerViewModule.java new file mode 100644 index 0000000000000000000000000000000000000000..64aa36b595255d5b0ff118c286b043e928f8826c --- /dev/null +++ b/android/src/main/java/com/beefe/picker/PickerViewModule.java @@ -0,0 +1,359 @@ +package com.beefe.picker; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.widget.PopupWindow; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.beefe.picker.view.OnSelectedListener; +import com.beefe.picker.view.PickerViewAlone; +import com.beefe.picker.view.PickerViewLinkage; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.core.DeviceEventManagerModule; + +import java.util.ArrayList; + +/** + * Created by heng on 16/9/5. + */ + +public class PickerViewModule extends ReactContextBaseJavaModule { + + private static final String REACT_CLASS = "BEEPickerManager"; + + private static final String PICKER_DATA = "pickerData"; + private static final String SELECTED_VALUE = "selectedValue"; + private static final String IS_LOOP = "isLoop"; + private static final String PICKER_BG_COLOR = "pickerBg"; + private static final String TEXT_BAR_COLOR = "pickerToolBarBg"; + private static final String CONFIRM_TEXT = "pickerConfirmBtnText"; + private static final String CONFIRM_TEXT_COLOR = "pickerConfirmBtnColor"; + private static final String CANCEL_TEXT = "pickerCancelBtnText"; + private static final String CANCEL_TEXT_COLOR = "pickerCancelBtnColor"; + private static final String TITLE_TEXT = "pickerTitleText"; + private static final String TITLE_TEXT_COLOR = "pickerTitleColor"; + + private static final String PICKER_EVENT_NAME = "pickerEvent"; + private static final String EVENT_KEY_CONFIRM = "confirm"; + private static final String EVENT_KEY_CANCEL = "cancel"; + private static final String EVENT_KEY_SELECTED = "select"; + + private static final String ERROR_NOT_INIT = "please initialize"; + + private View view; + private PopupWindow popupWindow = null; + + private boolean isLoop = true; + + private String confirmText; + private String cancelText; + private String titleText; + + private int[] pickerColor = new int[4]; + private int[] barBgColor = new int[4]; + private int[] confirmTextColor = new int[4]; + private int[] cancelTextColor = new int[4]; + private int[] titleTextColor = new int[4]; + + private ArrayList curSelectedList = new ArrayList<>(); + + private RelativeLayout pickerParent; + private RelativeLayout barLayout; + private TextView cancelTV; + private TextView titleTV; + private TextView confirmTV; + private PickerViewLinkage pickerViewLinkage; + private PickerViewAlone pickerViewAlone; + + public PickerViewModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return REACT_CLASS; + } + + @ReactMethod + public void _init(ReadableMap options) { + Activity activity = getCurrentActivity(); + if (activity != null && options.hasKey(PICKER_DATA)) { + view = activity.getLayoutInflater().inflate(R.layout.popup_picker_view, null); + + pickerParent = (RelativeLayout) view.findViewById(R.id.pickerParent); + barLayout = (RelativeLayout) view.findViewById(R.id.barLayout); + cancelTV = (TextView) view.findViewById(R.id.cancel); + titleTV = (TextView) view.findViewById(R.id.title); + confirmTV = (TextView) view.findViewById(R.id.confirm); + pickerViewLinkage = (PickerViewLinkage) view.findViewById(R.id.pickerViewLinkage); + pickerViewAlone = (PickerViewAlone) view.findViewById(R.id.pickerViewAlone); + + pickerParent.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + commonEvent(EVENT_KEY_CANCEL); + hide(); + } + }); + + if (options.hasKey(TEXT_BAR_COLOR)) { + ReadableArray array = options.getArray(TEXT_BAR_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + barBgColor[i] = (int) (array.getDouble(i) * 255); + } else { + barBgColor[i] = array.getInt(i); + } + } + barLayout.setBackgroundColor(Color.argb(barBgColor[3], barBgColor[0], barBgColor[1], barBgColor[2])); + } + + + if (options.hasKey(CONFIRM_TEXT)) { + confirmText = options.getString(CONFIRM_TEXT); + } + confirmTV.setText(!TextUtils.isEmpty(confirmText) ? confirmText : ""); + + if (options.hasKey(CONFIRM_TEXT_COLOR)) { + ReadableArray array = options.getArray(CONFIRM_TEXT_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + confirmTextColor[i] = (int) (array.getDouble(i) * 255); + } else { + confirmTextColor[i] = array.getInt(i); + } + } + confirmTV.setTextColor(Color.argb(confirmTextColor[3], confirmTextColor[0], confirmTextColor[1], confirmTextColor[2])); + } + confirmTV.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + commonEvent(EVENT_KEY_CONFIRM); + hide(); + } + }); + + + if (options.hasKey(TITLE_TEXT)) { + titleText = options.getString(TITLE_TEXT); + } + titleTV.setText(!TextUtils.isEmpty(titleText) ? titleText : ""); + if (options.hasKey(TITLE_TEXT_COLOR)) { + ReadableArray array = options.getArray(TITLE_TEXT_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + titleTextColor[i] = (int) (array.getDouble(i) * 255); + } else { + titleTextColor[i] = array.getInt(i); + } + } + titleTV.setTextColor(Color.argb(titleTextColor[3], titleTextColor[0], titleTextColor[1], titleTextColor[2])); + } + + if (options.hasKey(CANCEL_TEXT)) { + cancelText = options.getString(CANCEL_TEXT); + } + cancelTV.setText(!TextUtils.isEmpty(cancelText) ? cancelText : ""); + if (options.hasKey(CANCEL_TEXT_COLOR)) { + ReadableArray array = options.getArray(CANCEL_TEXT_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + cancelTextColor[i] = (int) (array.getDouble(i) * 255); + } else { + cancelTextColor[i] = array.getInt(i); + } + } + cancelTV.setTextColor(Color.argb(cancelTextColor[3], cancelTextColor[0], cancelTextColor[1], cancelTextColor[2])); + } + cancelTV.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + commonEvent(EVENT_KEY_CANCEL); + hide(); + } + }); + + if (options.hasKey(IS_LOOP)) { + isLoop = options.getBoolean(IS_LOOP); + } + + String[] selectValue = {}; + if (options.hasKey(SELECTED_VALUE)) { + ReadableArray array = options.getArray(SELECTED_VALUE); + selectValue = new String[array.size()]; + String value = ""; + for (int i = 0; i < array.size(); i++) { + switch (array.getType(i).name()) { + case "Boolean": + value = String.valueOf(array.getBoolean(i)); + break; + case "Number": + try { + value = String.valueOf(array.getInt(i)); + } catch (Exception e) { + value = String.valueOf(array.getDouble(i)); + } + break; + case "String": + value = array.getString(i); + break; + } + selectValue[i] = value; + } + } + + switch (options.getType(PICKER_DATA).name()) { + case "Map": + pickerViewLinkage.setVisibility(View.VISIBLE); + pickerViewAlone.setVisibility(View.GONE); + ReadableMap linkageData = options.getMap(PICKER_DATA); + if (linkageData != null) { + pickerViewLinkage.setLinkageData(linkageData, curSelectedList); + } + pickerViewLinkage.setIsLoop(isLoop); + if (options.hasKey(PICKER_BG_COLOR)) { + ReadableArray array = options.getArray(PICKER_BG_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + pickerColor[i] = (int) (array.getDouble(i) * 255); + } else { + pickerColor[i] = array.getInt(i); + } + } + pickerViewLinkage.setBackgroundColor(Color.argb(pickerColor[3], pickerColor[0], pickerColor[1], pickerColor[2])); + } + pickerViewLinkage.setOnSelectListener(new OnSelectedListener() { + @Override + public void onSelected(ArrayList selectedList) { + curSelectedList = selectedList; + commonEvent(EVENT_KEY_SELECTED); + } + }); + pickerViewLinkage.setSelectValue(selectValue, curSelectedList); + break; + case "Array": + pickerViewAlone.setVisibility(View.VISIBLE); + pickerViewLinkage.setVisibility(View.GONE); + ReadableArray aloneData = options.getArray(PICKER_DATA); + + if (aloneData != null) { + switch (aloneData.getType(0).name()) { + case "Array": + pickerViewAlone.setPickerViewDta(aloneData, curSelectedList); + break; + default: + pickerViewAlone.setAloneData(aloneData, curSelectedList); + break; + } + } + pickerViewAlone.setIsLoop(isLoop); + if (options.hasKey(PICKER_BG_COLOR)) { + ReadableArray array = options.getArray(PICKER_BG_COLOR); + for (int i = 0; i < array.size(); i++) { + if (i == 3) { + pickerColor[i] = (int) (array.getDouble(i) * 255); + } else { + pickerColor[i] = array.getInt(i); + } + } + pickerViewAlone.setBackgroundColor(Color.argb(pickerColor[3], pickerColor[0], pickerColor[1], pickerColor[2])); + } + + pickerViewAlone.setOnSelectedListener(new OnSelectedListener() { + @Override + public void onSelected(ArrayList selectedList) { + curSelectedList = selectedList; + commonEvent(EVENT_KEY_SELECTED); + } + }); + + pickerViewAlone.setSelectValue(selectValue, curSelectedList); + + break; + } + + if (popupWindow == null) { + popupWindow = new PopupWindow(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + popupWindow.setBackgroundDrawable(new ColorDrawable()); + popupWindow.setFocusable(true); + popupWindow.setAnimationStyle(R.style.PopAnim); + popupWindow.setOutsideTouchable(true); + } + popupWindow.setContentView(view); + popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0); + } + } + + @ReactMethod + public void initOK(Callback callback) { + callback.invoke(popupWindow != null); + } + + @ReactMethod + public void toggle() { + if (popupWindow == null) + return; + if (popupWindow.isShowing()) { + hide(); + } else { + show(); + } + } + + @ReactMethod + public void show() { + if (popupWindow != null) { + popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, 0); + } + } + + @ReactMethod + public void hide() { + if (popupWindow != null) { + popupWindow.dismiss(); + } + } + + @ReactMethod + public void isPickerShow(Callback callback) { + if (popupWindow == null) { + callback.invoke(ERROR_NOT_INIT); + } else { + callback.invoke(null, popupWindow.isShowing()); + } + } + + private void commonEvent(String eventKey) { + WritableMap map = Arguments.createMap(); + WritableArray array = Arguments.createArray(); + for (String item : curSelectedList) { + array.pushString(item); + } + map.putArray(eventKey, array); + sendEvent(getReactApplicationContext(), PICKER_EVENT_NAME, map); + } + + private void sendEvent(ReactContext reactContext, + String eventName, + @Nullable WritableMap params) { + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); + } +} diff --git a/android/src/main/java/com/beefe/picker/PickerViewPackage.java b/android/src/main/java/com/beefe/picker/PickerViewPackage.java new file mode 100644 index 0000000000000000000000000000000000000000..cd0bd4a37dab84459112972825731d37bf66b841 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/PickerViewPackage.java @@ -0,0 +1,33 @@ +package com.beefe.picker; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Created by heng on 16/9/5. + */ + +public class PickerViewPackage implements ReactPackage { + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new PickerViewModule(reactContext)); + } + + @Override + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/android/src/main/java/com/beefe/picker/view/InertiaTimerTask.java b/android/src/main/java/com/beefe/picker/view/InertiaTimerTask.java new file mode 100644 index 0000000000000000000000000000000000000000..391c113bda2ec4a846824bc98ee786d565827d08 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/InertiaTimerTask.java @@ -0,0 +1,56 @@ +package com.beefe.picker.view; + +import java.util.TimerTask; + +final class InertiaTimerTask extends TimerTask { + + float a; + final float velocityY; + final LoopView loopView; + + InertiaTimerTask(LoopView loopview, float velocityY) { + super(); + loopView = loopview; + this.velocityY = velocityY; + a = Integer.MAX_VALUE; + } + + @Override + public final void run() { + if (a == Integer.MAX_VALUE) { + if (Math.abs(velocityY) > 2000F) { + if (velocityY > 0.0F) { + a = 2000F; + } else { + a = -2000F; + } + } else { + a = velocityY; + } + } + if (Math.abs(a) >= 0.0F && Math.abs(a) <= 20F) { + loopView.cancelFuture(); + loopView.handler.sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL); + return; + } + int i = (int) ((a * 10F) / 1000F); + LoopView loopview = loopView; + loopview.totalScrollY = loopview.totalScrollY - i; + if (!loopView.isLoop) { + float itemHeight = loopView.lineSpacingMultiplier * loopView.maxTextHeight; + if (loopView.totalScrollY <= (int) ((float) (-loopView.initPosition) * itemHeight)) { + a = 40F; + loopView.totalScrollY = (int) ((float) (-loopView.initPosition) * itemHeight); + } else if (loopView.totalScrollY >= (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight)) { + loopView.totalScrollY = (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight); + a = -40F; + } + } + if (a < 0.0F) { + a = a + 20F; + } else { + a = a - 20F; + } + loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW); + } +} diff --git a/android/src/main/java/com/beefe/picker/view/LoopView.java b/android/src/main/java/com/beefe/picker/view/LoopView.java new file mode 100644 index 0000000000000000000000000000000000000000..df2f8c38496432c23768127c84b216aef7ccbc99 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/LoopView.java @@ -0,0 +1,431 @@ +package com.beefe.picker.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class LoopView extends View { + + private float scaleX = 1.05F; + + enum ACTION { + // 点击,滑翔(滑到尽头),拖拽事件 + CLICK, FLING, DRAG + } + + private Context context; + + Handler handler; + private GestureDetector gestureDetector; + OnItemSelectedListener onItemSelectedListener; + + // Timer mTimer; + private ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor(); + private ScheduledFuture mFuture; + + private Paint paintOuterText; + private Paint paintCenterText; + private Paint paintIndicator; + + List items; + + private int textSize; + int maxTextHeight; + + private int colorGray; + private int colorBlack; + private int colorLightGray; + + // 条目间距倍数 + float lineSpacingMultiplier; + boolean isLoop; + + // 第一条线Y坐标值 + private int firstLineY; + private int secondLineY; + + int totalScrollY; + int initPosition; + private String selectedItem; + private int selectedIndex; + private int preCurrentIndex; + + + // 显示几个条目 + private int itemsVisible; + + private int measuredHeight; + + // 半圆周长 + private int halfCircumference; + // 半径 + private int radius; + + private int mOffset = 0; + private float previousY; + private long startTime = 0; + + private Rect tempRect = new Rect(); + + public LoopView(Context context) { + super(context); + initLoopView(context); + } + + public LoopView(Context context, AttributeSet attributeset) { + super(context, attributeset); + initLoopView(context); + } + + public LoopView(Context context, AttributeSet attributeset, int defStyleAttr) { + super(context, attributeset, defStyleAttr); + initLoopView(context); + } + + private void initLoopView(Context context) { + this.context = context; + handler = new MessageHandler(this); + gestureDetector = new GestureDetector(context, new LoopViewGestureListener(this)); + gestureDetector.setIsLongpressEnabled(false); + + lineSpacingMultiplier = 2.0F; + isLoop = true; + itemsVisible = 9; + textSize = 0; + colorGray = 0xffafafaf; + colorBlack = 0xff313131; + colorLightGray = 0xffc5c5c5; + + totalScrollY = 0; + initPosition = -1; + + + initPaints(); + + setTextSize(20F); + } + + private void initPaints() { + paintOuterText = new Paint(); + paintOuterText.setColor(colorGray); + paintOuterText.setAntiAlias(true); + paintOuterText.setTypeface(Typeface.MONOSPACE); + paintOuterText.setTextSize(textSize); + + paintCenterText = new Paint(); + paintCenterText.setColor(colorBlack); + paintCenterText.setAntiAlias(true); + paintCenterText.setTextScaleX(scaleX); + paintCenterText.setTypeface(Typeface.MONOSPACE); + paintCenterText.setTextSize(textSize); + + paintIndicator = new Paint(); + paintIndicator.setColor(colorLightGray); + paintIndicator.setAntiAlias(true); + + if (android.os.Build.VERSION.SDK_INT >= 11) { + setLayerType(LAYER_TYPE_SOFTWARE, null); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + remeasure(); + setMeasuredDimension(widthMeasureSpec, measuredHeight); + } + + private void remeasure() { + if (items == null) { + return; + } + maxTextHeight = textSize; + + halfCircumference = (int) (maxTextHeight * lineSpacingMultiplier * (itemsVisible - 1)); + measuredHeight = (int) ((halfCircumference * 2) / Math.PI); + radius = (int) (halfCircumference / Math.PI); + firstLineY = (int) ((measuredHeight - lineSpacingMultiplier * maxTextHeight) / 2.0F); + secondLineY = (int) ((measuredHeight + lineSpacingMultiplier * maxTextHeight) / 2.0F); + if (initPosition == -1) { + if (isLoop) { + initPosition = (items.size() + 1) / 2; + } else { + initPosition = 0; + } + } + + preCurrentIndex = initPosition; + } + + void smoothScroll(ACTION action) { + cancelFuture(); + if (action == ACTION.FLING || action == ACTION.DRAG) { + float itemHeight = lineSpacingMultiplier * maxTextHeight; + mOffset = (int) ((totalScrollY % itemHeight + itemHeight) % itemHeight); + if ((float) mOffset > itemHeight / 2.0F) { + mOffset = (int) (itemHeight - (float) mOffset); + } else { + mOffset = -mOffset; + } + } + mFuture = mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS); + } + + + protected final void scrollBy(float velocityY) { + cancelFuture(); + // 修改这个值可以改变滑行速度 + int velocityFling = 10; + mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, velocityFling, TimeUnit.MILLISECONDS); + } + + public void cancelFuture() { + if (mFuture != null && !mFuture.isCancelled()) { + mFuture.cancel(true); + mFuture = null; + } + } + + public final void setNotLoop() { + isLoop = false; + } + + public final void setTextSize(float size) { + if (size > 0.0F) { + textSize = (int) (context.getResources().getDisplayMetrics().density * size); + paintOuterText.setTextSize(textSize); + paintCenterText.setTextSize(textSize); + } + } + + public boolean hasItem(String item) { + int result = items.indexOf(item); + return result != -1; + } + + public void setSelectedItem(String item) { + int selectedIndex = items.indexOf(item); + setSelectedPosition(selectedIndex); + } + + public int getItemPosition(String item) { + return items.indexOf(item); + } + + public final void setSelectedPosition(int initPosition) { + if (initPosition < 0) { + this.initPosition = 0; + } else { + if (items != null && items.size() > initPosition) { + this.initPosition = initPosition; + } + } + totalScrollY = 0; + cancelFuture(); + invalidate(); + } + + public final void setListener(OnItemSelectedListener OnItemSelectedListener) { + onItemSelectedListener = OnItemSelectedListener; + } + + public final void setItems(List items) { + this.items = items; + remeasure(); + invalidate(); + } + + public String getIndexItem(int index) { + return items.get(index); + } + public String getSelectedItem() { + return selectedItem; + } + + public final int getSelectedIndex() { + return selectedIndex; + } + + protected final void onItemSelected() { + if (onItemSelectedListener != null) { + postDelayed(new OnItemSelectedRunnable(this), 200L); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (items == null) { + return; + } + + String as[] = new String[itemsVisible]; + int change = (int) (totalScrollY / (lineSpacingMultiplier * maxTextHeight)); + preCurrentIndex = initPosition + change % items.size(); + + if (!isLoop) { + if (preCurrentIndex < 0) { + preCurrentIndex = 0; + } + if (preCurrentIndex > items.size() - 1) { + preCurrentIndex = items.size() - 1; + } + } else { + if (preCurrentIndex < 0) { + preCurrentIndex = items.size() + preCurrentIndex; + } + if (preCurrentIndex > items.size() - 1) { + preCurrentIndex = preCurrentIndex - items.size(); + } + } + + int j2 = (int) (totalScrollY % (lineSpacingMultiplier * maxTextHeight)); + // 设置as数组中每个元素的值 + int k1 = 0; + while (k1 < itemsVisible) { + int l1 = preCurrentIndex - (itemsVisible / 2 - k1); + if (isLoop) { + while (l1 < 0) { + l1 = l1 + items.size(); + } + while (l1 > items.size() - 1) { + l1 = l1 - items.size(); + } + as[k1] = items.get(l1); + } else if (l1 < 0) { + as[k1] = ""; + } else if (l1 > items.size() - 1) { + as[k1] = ""; + } else { + as[k1] = items.get(l1); + } + k1++; + } + canvas.drawLine(0.0F, firstLineY, getWidth(), firstLineY, paintIndicator); + canvas.drawLine(0.0F, secondLineY, getWidth(), secondLineY, paintIndicator); + + int j1 = 0; + while (j1 < itemsVisible) { + canvas.save(); + // L(弧长)=α(弧度)* r(半径) (弧度制) + // 求弧度--> (L * π ) / (π * r) (弧长X派/半圆周长) + float itemHeight = maxTextHeight * lineSpacingMultiplier; + double radian = ((itemHeight * j1 - j2) * Math.PI) / halfCircumference; + // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限 + float angle = (float) (90D - (radian / Math.PI) * 180D); + if (angle >= 90F || angle <= -90F) { + canvas.restore(); + } else { + int translateY = (int) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D); + canvas.translate(0.0F, translateY); + canvas.scale(1.0F, (float) Math.sin(radian)); + String text = as[j1]; + if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) { + // 条目经过第一条线 + canvas.save(); + canvas.clipRect(0, 0, getWidth(), firstLineY - translateY); + canvas.drawText(text, getX(text, paintOuterText), maxTextHeight, paintOuterText); + canvas.restore(); + canvas.save(); + canvas.clipRect(0, firstLineY - translateY, getWidth(), (int) (itemHeight)); + canvas.drawText(text, getX(text, paintCenterText), maxTextHeight, paintCenterText); + canvas.restore(); + } else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) { + // 条目经过第二条线 + canvas.save(); + canvas.clipRect(0, 0, getWidth(), secondLineY - translateY); + canvas.drawText(text, getX(text, paintCenterText), maxTextHeight, paintCenterText); + canvas.restore(); + canvas.save(); + canvas.clipRect(0, secondLineY - translateY, getWidth(), (int) (itemHeight)); + canvas.drawText(text, getX(text, paintOuterText), maxTextHeight, paintOuterText); + canvas.restore(); + } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) { + // 中间条目 + canvas.clipRect(0, 0, getWidth(), (int) (itemHeight)); + canvas.drawText(text, getX(text, paintCenterText), maxTextHeight, paintCenterText); + selectedItem = text; + selectedIndex = items.indexOf(text); + } else { + // 其他条目 + canvas.clipRect(0, 0, getWidth(), (int) (itemHeight)); + canvas.drawText(text, getX(text, paintOuterText), maxTextHeight, paintOuterText); + } + canvas.restore(); + } + j1++; + } + } + + private float getX(String text, Paint paint) { + paint.getTextBounds(text, 0, text.length(), tempRect); + return (getWidth() - tempRect.width() * scaleX) / 2; + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean eventConsumed = gestureDetector.onTouchEvent(event); + float itemHeight = lineSpacingMultiplier * maxTextHeight; + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + startTime = System.currentTimeMillis(); + cancelFuture(); + previousY = event.getRawY(); + break; + + case MotionEvent.ACTION_MOVE: + float dy = previousY - event.getRawY(); + previousY = event.getRawY(); + + totalScrollY = (int) (totalScrollY + dy); + + // 边界处理。 + if (!isLoop) { + float top = -initPosition * itemHeight; + float bottom = (items.size() - 1 - initPosition) * itemHeight; + + if (totalScrollY < top) { + totalScrollY = (int) top; + } else if (totalScrollY > bottom) { + totalScrollY = (int) bottom; + } + } + break; + + case MotionEvent.ACTION_UP: + default: + if (!eventConsumed) { + float y = event.getY(); + double l = Math.acos((radius - y) / radius) * radius; + int circlePosition = (int) ((l + itemHeight / 2) / itemHeight); + + float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight; + mOffset = (int) ((circlePosition - itemsVisible / 2) * itemHeight - extraOffset); + + if ((System.currentTimeMillis() - startTime) > 120) { + // 处理拖拽事件 + smoothScroll(ACTION.DRAG); + } else { + // 处理条目点击事件 + smoothScroll(ACTION.CLICK); + } + } + break; + } + invalidate(); + return true; + } +} diff --git a/android/src/main/java/com/beefe/picker/view/LoopViewGestureListener.java b/android/src/main/java/com/beefe/picker/view/LoopViewGestureListener.java new file mode 100644 index 0000000000000000000000000000000000000000..bd15bc4e851b0f228c49d45fa9cd83812cb7b125 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/LoopViewGestureListener.java @@ -0,0 +1,18 @@ +package com.beefe.picker.view; + +import android.view.MotionEvent; + +final class LoopViewGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { + + final LoopView loopView; + + LoopViewGestureListener(LoopView loopview) { + loopView = loopview; + } + + @Override + public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + loopView.scrollBy(velocityY); + return true; + } +} diff --git a/android/src/main/java/com/beefe/picker/view/MessageHandler.java b/android/src/main/java/com/beefe/picker/view/MessageHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..8bd1a7c4bce9697d88d0e16f0c2beac3be1a8c5f --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/MessageHandler.java @@ -0,0 +1,35 @@ +package com.beefe.picker.view; + +import android.os.Handler; +import android.os.Message; + +final class MessageHandler extends Handler { + + public static final int WHAT_INVALIDATE_LOOP_VIEW = 1000; + public static final int WHAT_SMOOTH_SCROLL = 2000; + public static final int WHAT_ITEM_SELECTED = 3000; + + final LoopView loopview; + + MessageHandler(LoopView loopview) { + this.loopview = loopview; + } + + @Override + public final void handleMessage(Message msg) { + switch (msg.what) { + case WHAT_INVALIDATE_LOOP_VIEW: + loopview.invalidate(); + break; + + case WHAT_SMOOTH_SCROLL: + loopview.smoothScroll(LoopView.ACTION.FLING); + break; + + case WHAT_ITEM_SELECTED: + loopview.onItemSelected(); + break; + } + } + +} diff --git a/android/src/main/java/com/beefe/picker/view/OnItemSelectedListener.java b/android/src/main/java/com/beefe/picker/view/OnItemSelectedListener.java new file mode 100644 index 0000000000000000000000000000000000000000..9e9e6856ecf84b59ba86c99091afb823ced0689d --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/OnItemSelectedListener.java @@ -0,0 +1,6 @@ +package com.beefe.picker.view; + + +public interface OnItemSelectedListener { + void onItemSelected(String item, int index); +} diff --git a/android/src/main/java/com/beefe/picker/view/OnItemSelectedRunnable.java b/android/src/main/java/com/beefe/picker/view/OnItemSelectedRunnable.java new file mode 100644 index 0000000000000000000000000000000000000000..c52b1a7e990bdcb33b6d65bc63452e7e34e19c7d --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/OnItemSelectedRunnable.java @@ -0,0 +1,15 @@ +package com.beefe.picker.view; + +final class OnItemSelectedRunnable implements Runnable { + + final LoopView loopView; + + OnItemSelectedRunnable(LoopView loopview) { + loopView = loopview; + } + + @Override + public final void run() { + loopView.onItemSelectedListener.onItemSelected(loopView.getSelectedItem(),loopView.getSelectedIndex()); + } +} diff --git a/android/src/main/java/com/beefe/picker/view/OnSelectedListener.java b/android/src/main/java/com/beefe/picker/view/OnSelectedListener.java new file mode 100644 index 0000000000000000000000000000000000000000..7122b26f17e52449b3a94f4c17a7049f92b8fb01 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/OnSelectedListener.java @@ -0,0 +1,13 @@ +package com.beefe.picker.view; + +import java.util.ArrayList; + +/** + * Created by heng on 16/9/6. + */ + +public interface OnSelectedListener { + + void onSelected(ArrayList selectedList); + +} diff --git a/android/src/main/java/com/beefe/picker/view/PickerViewAlone.java b/android/src/main/java/com/beefe/picker/view/PickerViewAlone.java new file mode 100644 index 0000000000000000000000000000000000000000..ef31445438aaf2d0247934f9daad927dc561d497 --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/PickerViewAlone.java @@ -0,0 +1,186 @@ +package com.beefe.picker.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import com.beefe.picker.R; +import com.facebook.react.bridge.ReadableArray; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Created by heng on 16/9/6. + */ + +public class PickerViewAlone extends LinearLayout { + + private LinearLayout pickerViewAloneLayout; + + private OnSelectedListener onSelectedListener; + + private int position; + + public PickerViewAlone(Context context) { + super(context); + init(context); + } + + public PickerViewAlone(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + private void init(Context context) { + View view = LayoutInflater.from(context).inflate(R.layout.picker_view_alone, this); + pickerViewAloneLayout = (LinearLayout) view.findViewById(R.id.pickerViewAloneLayout); + } + + public void setOnSelectedListener(OnSelectedListener listener) { + this.onSelectedListener = listener; + } + + public void setAloneData(ReadableArray array, final ArrayList curSelectedList) { + ArrayList values = arrayToList(array); + final LoopView loopView = new LoopView(getContext()); + LayoutParams params = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + params.weight = 1.0f; + loopView.setLayoutParams(params); + loopView.setItems(values); + loopView.setSelectedPosition(0); + if (curSelectedList.size() > 0) { + curSelectedList.set(0, values.get(0)); + } else { + curSelectedList.add(0, values.get(0)); + } + loopView.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + if (onSelectedListener != null) { + curSelectedList.set(0, item); + onSelectedListener.onSelected(curSelectedList); + } + } + }); + pickerViewAloneLayout.addView(loopView); + } + + + public void setPickerViewDta(ReadableArray array, final ArrayList curSelectedList) { + final String[] selectedItems = new String[array.size()]; + for (int i = 0; i < array.size(); i++) { + switch (array.getType(i).name()) { + case "Array": + ReadableArray childArray = array.getArray(i); + ArrayList values = arrayToList(childArray); + final LoopView loopView = new LoopView(getContext()); + LayoutParams params = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + params.weight = 1.0f; + loopView.setLayoutParams(params); + loopView.setItems(values); + loopView.setTag(i); + loopView.setSelectedPosition(0); + if (curSelectedList.size() > i) { + curSelectedList.set(i, values.get(0)); + } else { + curSelectedList.add(i, values.get(0)); + } + selectedItems[i] = values.get(0); + loopView.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + int viewCount = pickerViewAloneLayout.getChildCount(); + for (int j = 0; j < viewCount; j++) { + View view = pickerViewAloneLayout.getChildAt(j); + if (view instanceof LoopView) { + LoopView loop = (LoopView) view; + if (loop.getTag() == loopView.getTag()) { + position = j; + break; + } + } + } + selectedItems[position] = item; + if (onSelectedListener != null) { + for (int i = 0; i < selectedItems.length; i++) { + curSelectedList.set(i, selectedItems[i]); + } + onSelectedListener.onSelected(curSelectedList); + } + } + }); + pickerViewAloneLayout.addView(loopView); + break; + default: + break; + } + } + } + + public void setSelectValue(String[] selectValue, final ArrayList curSelectedList) { + int viewCount = pickerViewAloneLayout.getChildCount(); + int valueCount = selectValue.length; + if (valueCount <= viewCount) { + setSelect(valueCount, selectValue, curSelectedList); + } else { + String[] values = Arrays.copyOf(selectValue, viewCount); + setSelect(viewCount, values, curSelectedList); + } + } + + private void setSelect(int size, String[] values, ArrayList curSelectedList) { + for (int i = 0; i < size; i++) { + View view = pickerViewAloneLayout.getChildAt(i); + if (view instanceof LoopView) { + LoopView loop = (LoopView) view; + if (loop.hasItem(values[i])) { + loop.setSelectedItem(values[i]); + curSelectedList.set(i, values[i]); + } + } + } + } + + public void setIsLoop(boolean isLoop) { + if (!isLoop) { + int viewCount = pickerViewAloneLayout.getChildCount(); + for (int i = 0; i < viewCount; i++) { + View view = pickerViewAloneLayout.getChildAt(i); + if (view instanceof LoopView) { + LoopView loopView = (LoopView) view; + loopView.setNotLoop(); + } + } + } + } + + private ArrayList arrayToList(ReadableArray array) { + ArrayList values = new ArrayList<>(); + for (int i = 0; i < array.size(); i++) { + String value = ""; + switch (array.getType(i).name()) { + case "Boolean": + value = String.valueOf(array.getBoolean(i)); + break; + case "Number": + try { + value = String.valueOf(array.getInt(i)); + } catch (Exception e) { + value = String.valueOf(array.getDouble(i)); + } + break; + case "String": + value = array.getString(i); + break; + } + values.add(value); + } + return values; + } + +} diff --git a/android/src/main/java/com/beefe/picker/view/PickerViewLinkage.java b/android/src/main/java/com/beefe/picker/view/PickerViewLinkage.java new file mode 100644 index 0000000000000000000000000000000000000000..02f8ce3c393c94b1e295348342ccc4b125bb0a1d --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/PickerViewLinkage.java @@ -0,0 +1,426 @@ +package com.beefe.picker.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import com.beefe.picker.R; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableMapKeySetIterator; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Created by heng on 16/9/1. + */ + +public class PickerViewLinkage extends LinearLayout { + + private LoopView loopViewOne; + private LoopView loopViewTwo; + private LoopView loopViewThree; + + private OnSelectedListener onSelectedListener; + + private int curRow; + + public PickerViewLinkage(Context context) { + super(context); + init(context); + } + + public PickerViewLinkage(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public PickerViewLinkage(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + View view = LayoutInflater.from(context).inflate(R.layout.picker_view_linkage, this); + loopViewOne = (LoopView) view.findViewById(R.id.loopViewOne); + loopViewTwo = (LoopView) view.findViewById(R.id.loopViewTwo); + loopViewThree = (LoopView) view.findViewById(R.id.loopViewThree); + } + + private void setRow(int row) { + switch (row) { + case 2: + curRow = 2; + loopViewTwo.setVisibility(VISIBLE); + loopViewOne.setVisibility(VISIBLE); + loopViewThree.setVisibility(GONE); + break; + case 3: + curRow = 3; + loopViewOne.setVisibility(VISIBLE); + loopViewTwo.setVisibility(VISIBLE); + loopViewThree.setVisibility(VISIBLE); + break; + default: + break; + } + } + + private ArrayList oneList = new ArrayList<>(); + private ArrayList twoList = new ArrayList<>(); + private ArrayList threeList = new ArrayList<>(); + + private ReadableArray array; + private ReadableMap map; + private ReadableMap childMap; + + private int selectOneIndex; + private int selectTwoIndex; + + private void checkItems(LoopView loopView, ArrayList list) { + if (list != null && list.size() > 0) { + loopView.setItems(list); + loopView.setSelectedPosition(0); + } + } + + public void setLinkageData(final ReadableMap map, final ArrayList curSelectedList) { + this.map = map; + ReadableMapKeySetIterator iterator = map.keySetIterator(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + oneList.add(key); + } + checkItems(loopViewOne, oneList); + if (curSelectedList.size() > 0) { + curSelectedList.set(0, oneList.get(0)); + } else { + curSelectedList.add(0, oneList.get(0)); + } + String name = map.getType(oneList.get(0)).name(); + switch (name) { + case "Map": + setRow(3); + childMap = map.getMap(oneList.get(0)); + ReadableMapKeySetIterator childIterator = childMap.keySetIterator(); + twoList.clear(); + while (childIterator.hasNextKey()) { + String key = childIterator.nextKey(); + twoList.add(key); + } + checkItems(loopViewTwo, twoList); + if (curSelectedList.size() > 1) { + curSelectedList.set(1, twoList.get(0)); + } else { + curSelectedList.add(1, twoList.get(0)); + } + + array = childMap.getArray(twoList.get(0)); + threeList.clear(); + threeList = arrayToList(array); + checkItems(loopViewThree, threeList); + if (curSelectedList.size() > 2) { + curSelectedList.set(2, threeList.get(0)); + } else { + curSelectedList.add(2, threeList.get(0)); + } + + loopViewOne.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + selectOneIndex = index; + curSelectedList.set(0, item); + + childMap = map.getMap(item); + ReadableMapKeySetIterator childIterator = childMap.keySetIterator(); + twoList.clear(); + while (childIterator.hasNextKey()) { + String key = childIterator.nextKey(); + twoList.add(key); + } + checkItems(loopViewTwo, twoList); + curSelectedList.set(1, twoList.get(0)); + + array = childMap.getArray(twoList.get(0)); + threeList.clear(); + threeList = arrayToList(array); + checkItems(loopViewThree, threeList); + curSelectedList.set(2, threeList.get(0)); + + if (onSelectedListener != null) { + onSelectedListener.onSelected(curSelectedList); + } + } + }); + + loopViewTwo.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + selectTwoIndex = index; + array = childMap.getArray(item); + threeList.clear(); + threeList = arrayToList(array); + checkItems(loopViewThree, threeList); + + curSelectedList.set(0, oneList.get(selectOneIndex)); + curSelectedList.set(1, item); + curSelectedList.set(2, threeList.get(0)); + if (onSelectedListener != null) { + onSelectedListener.onSelected(curSelectedList); + } + } + }); + + loopViewThree.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + curSelectedList.set(0, oneList.get(selectOneIndex)); + curSelectedList.set(1, twoList.get(selectTwoIndex)); + curSelectedList.set(2, item); + if (onSelectedListener != null) { + onSelectedListener.onSelected(curSelectedList); + } + } + }); + break; + case "Array": + setRow(2); + loopViewOne.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + selectOneIndex = index; + array = map.getArray(item); + twoList = arrayToList(array); + checkItems(loopViewTwo, twoList); + curSelectedList.set(0, item); + curSelectedList.set(1, twoList.get(0)); + if (onSelectedListener != null) { + onSelectedListener.onSelected(curSelectedList); + } + } + }); + + array = map.getArray(oneList.get(0)); + twoList = arrayToList(array); + checkItems(loopViewTwo, twoList); + curSelectedList.add(1, twoList.get(0)); + loopViewTwo.setListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(String item, int index) { + curSelectedList.set(0, oneList.get(selectOneIndex)); + curSelectedList.set(1, item); + if (onSelectedListener != null) { + onSelectedListener.onSelected(curSelectedList); + } + } + }); + break; + default: + break; + } + } + + private ArrayList arrayToList(ReadableArray array) { + try { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < array.size(); i++) { + String values = ""; + switch (array.getType(i).name()) { + case "Boolean": + values = String.valueOf(array.getBoolean(i)); + break; + case "Number": + try { + values = String.valueOf(array.getInt(i)); + } catch (Exception e) { + values = String.valueOf(array.getDouble(i)); + } + break; + case "String": + values = array.getString(i); + break; + } + list.add(values); + } + return list; + } catch (Exception e) { + return null; + } + } + + public void setSelectValue(String[] selectValue, final ArrayList curSelectedList) { + if (curRow <= selectValue.length) { + String[] values = Arrays.copyOf(selectValue, curRow); + selectValues(values, curSelectedList); + } else { + switch (selectValue.length) { + case 1: + if (loopViewOne.hasItem(selectValue[0])) { + selectOneIndex = loopViewOne.getItemPosition(selectValue[0]); + loopViewOne.setSelectedPosition(selectOneIndex); + curSelectedList.set(0, loopViewOne.getIndexItem(selectOneIndex)); + } else { + loopViewOne.setSelectedPosition(0); + curSelectedList.set(0, loopViewOne.getIndexItem(0)); + } + switch (curRow) { + case 3: + childMap = map.getMap(oneList.get(selectOneIndex)); + ReadableMapKeySetIterator childIterator = childMap.keySetIterator(); + twoList.clear(); + while (childIterator.hasNextKey()) { + String key = childIterator.nextKey(); + twoList.add(key); + } + + loopViewTwo.setItems(twoList); + loopViewTwo.setSelectedPosition(0); + curSelectedList.set(1, loopViewTwo.getIndexItem(0)); + + array = childMap.getArray(twoList.get(0)); + threeList.clear(); + threeList = arrayToList(array); + loopViewThree.setItems(threeList); + loopViewThree.setSelectedPosition(0); + curSelectedList.set(2, loopViewThree.getIndexItem(0)); + + break; + case 2: + array = map.getArray(oneList.get(selectOneIndex)); + twoList = arrayToList(array); + loopViewTwo.setItems(twoList); + loopViewTwo.setSelectedPosition(0); + curSelectedList.set(1, loopViewTwo.getIndexItem(0)); + break; + } + break; + case 2: + switch (curRow) { + case 3: + if (loopViewOne.hasItem(selectValue[0])) { + selectOneIndex = loopViewOne.getItemPosition(selectValue[0]); + loopViewOne.setSelectedPosition(selectOneIndex); + curSelectedList.set(0, loopViewOne.getIndexItem(selectOneIndex)); + } else { + loopViewOne.setSelectedPosition(0); + curSelectedList.set(0, loopViewOne.getIndexItem(0)); + } + + childMap = map.getMap(oneList.get(selectOneIndex)); + ReadableMapKeySetIterator childIterator = childMap.keySetIterator(); + twoList.clear(); + while (childIterator.hasNextKey()) { + String key = childIterator.nextKey(); + twoList.add(key); + } + loopViewTwo.setItems(twoList); + if (loopViewTwo.hasItem(selectValue[1])) { + selectTwoIndex = loopViewTwo.getItemPosition(selectValue[1]); + loopViewTwo.setSelectedPosition(selectTwoIndex); + curSelectedList.set(1, loopViewTwo.getIndexItem(selectTwoIndex)); + } else { + loopViewTwo.setSelectedPosition(0); + curSelectedList.set(1, loopViewTwo.getIndexItem(0)); + } + + array = childMap.getArray(twoList.get(selectTwoIndex)); + threeList.clear(); + threeList = arrayToList(array); + loopViewThree.setItems(threeList); + loopViewThree.setSelectedPosition(0); + curSelectedList.set(2, loopViewThree.getIndexItem(0)); + break; + } + break; + default: + break; + } + } + } + + private void selectValues(String[] values, final ArrayList curSelectedList) { + switch (values.length) { + case 3: + if (loopViewOne.hasItem(values[0])) { + selectOneIndex = loopViewOne.getItemPosition(values[0]); + loopViewOne.setSelectedPosition(selectOneIndex); + curSelectedList.set(0, loopViewOne.getIndexItem(selectOneIndex)); + } else { + loopViewOne.setSelectedPosition(0); + curSelectedList.set(0, loopViewOne.getIndexItem(0)); + } + + childMap = map.getMap(oneList.get(selectOneIndex)); + ReadableMapKeySetIterator childIterator = childMap.keySetIterator(); + twoList.clear(); + while (childIterator.hasNextKey()) { + String key = childIterator.nextKey(); + twoList.add(key); + } + loopViewTwo.setItems(twoList); + if (loopViewTwo.hasItem(values[1])) { + selectTwoIndex = loopViewTwo.getItemPosition(values[1]); + loopViewTwo.setSelectedPosition(selectTwoIndex); + curSelectedList.set(1, loopViewTwo.getIndexItem(selectTwoIndex)); + } else { + loopViewTwo.setSelectedPosition(0); + curSelectedList.set(1, loopViewTwo.getIndexItem(0)); + } + + array = childMap.getArray(twoList.get(selectTwoIndex)); + threeList.clear(); + threeList = arrayToList(array); + loopViewThree.setItems(threeList); + if (loopViewThree.hasItem(values[2])) { + int selectThreeIndex = loopViewThree.getItemPosition(values[2]); + loopViewThree.setSelectedPosition(selectThreeIndex); + curSelectedList.set(2, loopViewThree.getIndexItem(selectThreeIndex)); + } else { + loopViewThree.setSelectedPosition(0); + curSelectedList.set(2, loopViewThree.getIndexItem(0)); + } + break; + case 2: + if (loopViewOne.hasItem(values[0])) { + selectOneIndex = loopViewOne.getItemPosition(values[0]); + loopViewOne.setSelectedPosition(selectOneIndex); + curSelectedList.set(0, loopViewOne.getIndexItem(selectOneIndex)); + } else { + loopViewOne.setSelectedPosition(0); + curSelectedList.set(0, loopViewOne.getIndexItem(0)); + } + + array = map.getArray(oneList.get(selectOneIndex)); + twoList = arrayToList(array); + loopViewTwo.setItems(twoList); + if (loopViewTwo.hasItem(values[1])) { + selectTwoIndex = loopViewTwo.getItemPosition(values[1]); + loopViewTwo.setSelectedPosition(selectTwoIndex); + curSelectedList.set(1, loopViewTwo.getIndexItem(selectTwoIndex)); + } else { + loopViewTwo.setSelectedPosition(0); + curSelectedList.set(1, loopViewTwo.getIndexItem(0)); + } + break; + default: + break; + } + } + + + public void setIsLoop(boolean isLoop) { + if (!isLoop) { + loopViewOne.setNotLoop(); + loopViewTwo.setNotLoop(); + loopViewThree.setNotLoop(); + } + } + + public void setOnSelectListener(OnSelectedListener listener) { + this.onSelectedListener = listener; + } + +} diff --git a/android/src/main/java/com/beefe/picker/view/SmoothScrollTimerTask.java b/android/src/main/java/com/beefe/picker/view/SmoothScrollTimerTask.java new file mode 100644 index 0000000000000000000000000000000000000000..93a8ae53daf37736eae3cdfed52f9cb9c1caad0e --- /dev/null +++ b/android/src/main/java/com/beefe/picker/view/SmoothScrollTimerTask.java @@ -0,0 +1,42 @@ +package com.beefe.picker.view; + +import java.util.TimerTask; + +final class SmoothScrollTimerTask extends TimerTask { + + int realTotalOffset; + int realOffset; + int offset; + final LoopView loopView; + + SmoothScrollTimerTask(LoopView loopview, int offset) { + this.loopView = loopview; + this.offset = offset; + realTotalOffset = Integer.MAX_VALUE; + realOffset = 0; + } + + @Override + public final void run() { + if (realTotalOffset == Integer.MAX_VALUE) { + realTotalOffset = offset; + } + realOffset = (int) ((float) realTotalOffset * 0.1F); + + if (realOffset == 0) { + if (realTotalOffset < 0) { + realOffset = -1; + } else { + realOffset = 1; + } + } + if (Math.abs(realTotalOffset) <= 0) { + loopView.cancelFuture(); + loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED); + } else { + loopView.totalScrollY = loopView.totalScrollY + realOffset; + loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW); + realTotalOffset = realTotalOffset - realOffset; + } + } +} diff --git a/android/src/main/res/anim/popup_enter.xml b/android/src/main/res/anim/popup_enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcd9d38c5a317f05619b01aa79fa3f1ffcccb0c4 --- /dev/null +++ b/android/src/main/res/anim/popup_enter.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/res/anim/popup_exit.xml b/android/src/main/res/anim/popup_exit.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f60348e1e5e029d98d1a3e4398fdede8c5dcf49 --- /dev/null +++ b/android/src/main/res/anim/popup_exit.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/res/layout/picker_view_alone.xml b/android/src/main/res/layout/picker_view_alone.xml new file mode 100644 index 0000000000000000000000000000000000000000..aae23037ba7e5bb1c7fc11954ba61d339affbb1c --- /dev/null +++ b/android/src/main/res/layout/picker_view_alone.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/android/src/main/res/layout/picker_view_linkage.xml b/android/src/main/res/layout/picker_view_linkage.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c26d8ba24cf782b8de4d627ddb56429678561db --- /dev/null +++ b/android/src/main/res/layout/picker_view_linkage.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/res/layout/popup_picker_view.xml b/android/src/main/res/layout/popup_picker_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f435a2bc3b6c696e9c57248c9b3e06fe3747b6d --- /dev/null +++ b/android/src/main/res/layout/popup_picker_view.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..c0abaaf25a432f704f8561c3a30caa3facd03906 --- /dev/null +++ b/android/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + react-native-picker + diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..d4b7e056e0c79b5a033f3b8e14ab2e107ad3f800 --- /dev/null +++ b/android/src/main/res/values/styles.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/example/PickerTest/index.android.js b/example/PickerTest/index.android.js index 1c8a8f19b4ba6a711a2e358688b24b57f4ace910..eace2754e888a939ea378946c8a60a07630fb259 100644 --- a/example/PickerTest/index.android.js +++ b/example/PickerTest/index.android.js @@ -50,7 +50,23 @@ class PickerTest extends Component { } _onPressHandle() { - this.picker.toggle(); + Picker.init({ + pickerData: createDateData(), + selectedValue: ['2015年', '12月', '12日'], + onPickerConfirm: pickedValue => { + alert(JSON.stringify(pickedValue)); + console.log(pickedValue); + }, + onPickerCancel: pickedValue => { + alert(JSON.stringify(pickedValue)); + console.log(pickedValue); + }, + onPickerSelect: pickedValue => { + alert(JSON.stringify(pickedValue)); + console.log(pickedValue); + } + }); + Picker.show(); } render() { @@ -59,18 +75,6 @@ class PickerTest extends Component { Click Me - this.picker = picker} - style={{height: 260}} - showDuration={300} - showMask={true} - pickerData={createDateData()} - selectedValue={['2015年', '12月', '12日']} - onPickerDone={(pickedValue) => { - alert(JSON.stringify(pickedValue)); - console.log(pickedValue); - }} - /> ); } diff --git a/example/PickerTest/package.json b/example/PickerTest/package.json index 28301bbbf35a4936dd89a87140a7291d24db761b..bf925b5022e99715639bcb20e9276e0e7e9d1ef4 100644 --- a/example/PickerTest/package.json +++ b/example/PickerTest/package.json @@ -8,6 +8,6 @@ "dependencies": { "react": "15.0.2", "react-native": "^0.26.1", - "react-native-picker": "^3.0.3" + "react-native-picker": "beefe/react-native-picker" } } diff --git a/index.js b/index.js index f53088c0a2af120ee71fed75eea53533b2f2c287..d5d9c279f935828129fa7d7f3c36e94eb648172b 100644 --- a/index.js +++ b/index.js @@ -1,511 +1,77 @@ -'use strict'; - -import React, {Component, PropTypes} from 'react'; import { - StyleSheet, - View, - Text, - Animated, - Platform, - Dimensions, - PickerIOS + Platform, + NativeModules, + NativeAppEventEmitter } from 'react-native'; -import PickerAndroid from 'react-native-picker-android'; - -let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid; -let PickerItem = Picker.Item; -let {width, height} = Dimensions.get('window'); - -const longSide = width > height ? width : height; -const shortSide = width > height ? height : width; - -export default class PickerAny extends Component { - - static propTypes = { - style: View.propTypes.style, - pickerElevation: PropTypes.number, - pickerBtnText: PropTypes.string, - pickerCancelBtnText: PropTypes.string, - pickerBtnStyle: Text.propTypes.style, - pickerTitle: PropTypes.string, - pickerTitleStyle: Text.propTypes.style, - pickerToolBarStyle: View.propTypes.style, - showMask: PropTypes.bool, - showDuration: PropTypes.number, - pickerData: PropTypes.any.isRequired, - selectedValue: PropTypes.any.isRequired, - onPickerDone: PropTypes.func, - onPickerCancel: PropTypes.func, - onValueChange: PropTypes.func - }; - - static defaultProps = { - style: { - width: width - }, - pickerBtnText: 'Done', - pickerCancelBtnText: 'Cancel', - showMask: false, - showDuration: 300, - onPickerDone: ()=>{}, - onPickerCancel: ()=>{}, - onValueChange: ()=>{} - }; - - constructor(props, context){ - super(props, context); - } - - componentWillMount(){ - this.state = this._getStateFromProps(this.props); - } - - componentWillReceiveProps(newProps){ - let newState = this._getStateFromProps(newProps); - this.setState(newState); - } - - shouldComponentUpdate(nextProps, nextState, context){ - return true; - } - - _getStateFromProps(props){ - //the pickedValue must looks like [wheelone's, wheeltwo's, ...] - //this.state.selectedValue may be the result of the first pickerWheel - let {pickerData, selectedValue} = props; - let pickerStyle = pickerData.constructor === Array ? 'parallel' : 'cascade'; - let firstWheelData; - let firstPickedData; - let secondPickedData; - let secondWheelData; - let secondPickedDataIndex; - let thirdWheelData; - let thirdPickedDataIndex; - let cascadeData = {}; - let slideAnim = (this.state && this.state.slideAnim ? this.state.slideAnim : new Animated.Value(-height)); - - if(pickerStyle === 'parallel'){ - //compatible single wheel sence - if(selectedValue.constructor !== Array){ - selectedValue = [selectedValue]; - } - if(pickerData[0].constructor !== Array){ - pickerData = [pickerData]; - } - } - else if(pickerStyle === 'cascade'){ - //only support three stage - firstWheelData = Object.keys(pickerData); - firstPickedData = props.selectedValue[0]; - secondPickedData = props.selectedValue[1]; - cascadeData = this._getCascadeData(pickerData, selectedValue, firstPickedData, secondPickedData, true); - } - //save picked data - this.pickedValue = JSON.parse(JSON.stringify(selectedValue)); - this.pickerStyle = pickerStyle; - return { - ...props, - pickerData, - selectedValue, - //list of first wheel data - firstWheelData, - //first wheel selected value - firstPickedData, - slideAnim, - //list of second wheel data and pickedDataIndex - secondWheelData: cascadeData.secondWheelData, - secondPickedDataIndex: cascadeData.secondPickedDataIndex, - //third wheel selected value and pickedDataIndex - thirdWheelData: cascadeData.thirdWheelData, - thirdPickedDataIndex: cascadeData.thirdPickedDataIndex - }; - } - - _slideUp(){ - this._isMoving = true; - Animated.timing( - this.state.slideAnim, - { - toValue: 0, - duration: this.state.showDuration, - } - ).start((evt) => { - if(evt.finished) { - this._isMoving = false; - this._isPickerShow = true; - } - }); - } - - _slideDown(){ - this._isMoving = true; - Animated.timing( - this.state.slideAnim, - { - toValue: -height, - duration: this.state.showDuration, - } - ).start((evt) => { - if(evt.finished) { - this._isMoving = false; - this._isPickerShow = false; - } - }); - } - - _toggle(){ - if(this._isMoving) { - return; - } - if(this._isPickerShow) { - this._slideDown(); - } - else{ - this._slideUp(); - } - } - - toggle(){ - this._toggle(); - } - show(){ - if(!this._isPickerShow){ - this._slideUp(); - } - } - hide(){ - if(this._isPickerShow){ - this._slideDown(); - } - } - isPickerShow(){ - return this._isPickerShow; - } - - _prePressHandle(callback){ - this.pickerWheel.moveUp(); - } - - _nextPressHandle(callback){ - this.pickerWheel.moveDown(); - } - - _pickerCancel(){ - this._toggle(); - this.state.onPickerCancel(); - } - - _pickerFinish(){ - this._toggle(); - this.state.onPickerDone(this.pickedValue); - } - - _renderParallelWheel(pickerData){ - return pickerData.map((item, index) => { - return ( - - { - this.pickedValue.splice(index, 1, value); - //do not set state to another object!! why? - // this.setState({ - // selectedValue: this.pickedValue - // }); - this.setState({ - selectedValue: JSON.parse(JSON.stringify(this.pickedValue)) - }); - this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), index); - }} > - {item.map((value, index) => ( - ) - )} - - - ); - }); - } - - _getCascadeData(pickerData, pickedValue, firstPickedData, secondPickedData, onInit){ - let secondWheelData; - let secondPickedDataIndex; - let thirdWheelData; - let thirdPickedDataIndex; - //only support two and three stage - for(let key in pickerData){ - //two stage - if(pickerData[key].constructor === Array){ - secondWheelData = pickerData[firstPickedData]; - if(onInit){ - secondWheelData.forEach(function(v, k){ - if(v === pickedValue[1]){ - secondPickedDataIndex = k; - } - }.bind(this)); - } - else{ - secondPickedDataIndex = 0; - } - break; - } - //three stage - else{ - secondWheelData = Object.keys(pickerData[firstPickedData]); - if(onInit){ - secondWheelData.forEach(function(v, k){ - if(v === pickedValue[1]){ - secondPickedDataIndex = k; - } - }.bind(this)); - } - else{ - secondPickedDataIndex = 0; - } - thirdWheelData = pickerData[firstPickedData][secondPickedData]; - if(onInit){ - thirdWheelData.forEach(function(v, k){ - if(v === pickedValue[2]){ - thirdPickedDataIndex = k; - } - }) - } - else{ - thirdPickedDataIndex = 0; - } - break; - } - } - - return { - secondWheelData, - secondPickedDataIndex, - thirdWheelData, - thirdPickedDataIndex - } - } - - _renderCascadeWheel(pickerData){ - let thirdWheel = this.state.thirdWheelData && ( - - { - this.pickedValue.splice(2, 1, this.state.thirdWheelData[index]); - this.setState({ - thirdPickedDataIndex: index, - selectedValue: 'wheel3'+index - }); - this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 2); - }} > - {this.state.thirdWheelData.map((value, index) => ( - ) - )} - - - ); - - return ( - - - { - let secondWheelData = Object.keys(pickerData[value]); - let cascadeData = this._getCascadeData(pickerData, this.pickedValue, value, secondWheelData[0]); - //when onPicked, this.pickedValue will pass to the parent - //when firstWheel changed, second and third will also change - if(cascadeData.thirdWheelData){ - this.pickedValue.splice(0, 3, value, cascadeData.secondWheelData[0], cascadeData.thirdWheelData[0]); - } - else{ - this.pickedValue.splice(0, 2, value, cascadeData.secondWheelData[0]); - } - - this.setState({ - selectedValue: 'wheel1'+value, - firstPickedData: value, - secondWheelData: cascadeData.secondWheelData, - secondPickedDataIndex: 0, - thirdWheelData: cascadeData.thirdWheelData, - thirdPickedDataIndex: 0 - }); - this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 0); - this.refs.secondWheel && this.refs.secondWheel.moveTo && this.refs.secondWheel.moveTo(0); - this.refs.thirdWheel && this.refs.thirdWheel.moveTo && this.refs.thirdWheel.moveTo(0); - }} > - {this.state.firstWheelData.map((value, index) => ( - ) - )} - - - - { - let thirdWheelData = pickerData[this.state.firstPickedData][this.state.secondWheelData[index]]; - if(thirdWheelData){ - this.pickedValue.splice(1, 2, this.state.secondWheelData[index], thirdWheelData[0]); - } - else{ - this.pickedValue.splice(1, 1, this.state.secondWheelData[index]); - } - - this.setState({ - secondPickedDataIndex: index, - thirdWheelData, - thirdPickedDataIndex: 0, - selectedValue: 'wheel2'+index - }); - this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 1); - this.refs.thirdWheel && this.refs.thirdWheel.moveTo && this.refs.thirdWheel.moveTo(0); - }} > - {this.state.secondWheelData.map((value, index) => ( - ) - )} - - - {thirdWheel} - - ); - } - - _renderWheel(pickerData){ - let wheel = null; - if(this.pickerStyle === 'parallel'){ - wheel = this._renderParallelWheel(pickerData); - } - else if(this.pickerStyle === 'cascade'){ - wheel = this._renderCascadeWheel(pickerData); - } - return wheel; - } - - render(){ - - let mask = this.state.showMask ? ( - - - - ) : null; - - return ( - - {mask} - - - - {this.state.pickerCancelBtnText} - - - {this.state.pickerTitle} - - - {this.state.pickerBtnText} - - - - {this._renderWheel(this.state.pickerData)} - - - - ); - } -}; - -let styles = StyleSheet.create({ - picker: { - position: 'absolute', - bottom: 0, - left: 0, - backgroundColor: 'transparent', - }, - pickerBox: { - position: 'absolute', - bottom: 0, - left: 0, - backgroundColor: '#bdc0c7' - }, - mask: { - position: 'absolute', - top: 0, - backgroundColor: 'transparent', - height: height, - width: width - }, - pickerWrap: { - flexDirection: 'row' - }, - pickerWheel: { - flex: 1 - }, - pickerToolbar: { - height: 30, - backgroundColor: '#e6e6e6', - flexDirection: 'row', - borderTopWidth: 1, - borderBottomWidth: 1, - borderColor: '#c3c3c3', - alignItems: 'center' - }, - pickerBtnView: { - flex: 1, - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center' - }, - pickerMoveBtn: { - color: '#149be0', - fontSize: 16, - marginLeft: 20 - }, - pickerCancelBtn: { - flex: 1, - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - marginLeft: 20 - }, - pickerTitle: { - flex: 4, - color: 'black', - textAlign: 'center' - }, - pickerFinishBtn: { - flex: 1, - flexDirection: 'row', - justifyContent: 'flex-end', - alignItems: 'center', - marginRight: 20 - }, - pickerFinishBtnText: { - fontSize: 16, - color: '#149be0' - } -}); +let ios = Platform.OS === 'ios'; +let android = Platform.OS === 'android'; +let Picker = NativeModules.BEEPickerManager; + +export default { + + init(options){ + let opt = { + isLoop: false, + pickerConfirmBtnText: '确认', + pickerCancelBtnText: '取消', + pickerTitleText: '请选择', + pickerBg: [196, 199, 206, 1], + pickerToolBarBg: [232, 232, 232, 1], + pickerTitleColor: [20, 20, 20, 1], + pickerCancelBtnColor: [1, 186, 245, 1], + pickerConfirmBtnColor: [1, 186, 245, 1], + onPickerConfirm(){}, + onPickerCancel(){}, + onPickerSelect(){}, + ...options + }; + let fnConf = { + confirm: opt.onPickerConfirm, + cancel: opt.onPickerCancel, + select: opt.onPickerSelect + }; + + Picker._init(opt); + if(this.inited){ + return; + } + this.inited = true; + + NativeAppEventEmitter.addListener('pickerEvent', event => { + if(ios){ + fnConf[event['type']](event['selectedValue']); + } + else if(android){ + for (let i in event){ + typeof fnConf[i] === 'function' && fnConf[i](event[i]); + } + } + }); + }, + + show(){ + Picker.show(); + }, + + hide(){ + Picker.hide(); + }, + + toggle(){ + this.isPickerShow(show => { + if(show){ + this.hide(); + } + else{ + this.show(); + } + }); + }, + + isPickerShow(fn){ + Picker.isPickerShow(hide => { + fn(!hide); + }); + } +}; \ No newline at end of file diff --git a/ios/RCTBEEPickerManager.xcodeproj/project.pbxproj b/ios/RCTBEEPickerManager.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000000000000000000000000000000..635f78ee3cd61bf904020590501eab6f47aaa673 --- /dev/null +++ b/ios/RCTBEEPickerManager.xcodeproj/project.pbxproj @@ -0,0 +1,267 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 17D41E591D7EE0CA0031415E /* RCTBEEPickerManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17D41E581D7EE0CA0031415E /* RCTBEEPickerManager.h */; }; + 17D41E5B1D7EE0CA0031415E /* RCTBEEPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D41E5A1D7EE0CA0031415E /* RCTBEEPickerManager.m */; }; + 17D41E631D7EE0EE0031415E /* BzwPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 17D41E621D7EE0EE0031415E /* BzwPicker.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 17D41E531D7EE0CA0031415E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + 17D41E591D7EE0CA0031415E /* RCTBEEPickerManager.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 17D41E551D7EE0CA0031415E /* libRCTBEEPickerManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBEEPickerManager.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 17D41E581D7EE0CA0031415E /* RCTBEEPickerManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBEEPickerManager.h; sourceTree = ""; }; + 17D41E5A1D7EE0CA0031415E /* RCTBEEPickerManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTBEEPickerManager.m; sourceTree = ""; }; + 17D41E611D7EE0EE0031415E /* BzwPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BzwPicker.h; sourceTree = ""; }; + 17D41E621D7EE0EE0031415E /* BzwPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BzwPicker.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 17D41E521D7EE0CA0031415E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 17D41E4C1D7EE0CA0031415E = { + isa = PBXGroup; + children = ( + 17D41E571D7EE0CA0031415E /* RCTBEEPickerManager */, + 17D41E561D7EE0CA0031415E /* Products */, + ); + sourceTree = ""; + }; + 17D41E561D7EE0CA0031415E /* Products */ = { + isa = PBXGroup; + children = ( + 17D41E551D7EE0CA0031415E /* libRCTBEEPickerManager.a */, + ); + name = Products; + sourceTree = ""; + }; + 17D41E571D7EE0CA0031415E /* RCTBEEPickerManager */ = { + isa = PBXGroup; + children = ( + 17D41E611D7EE0EE0031415E /* BzwPicker.h */, + 17D41E621D7EE0EE0031415E /* BzwPicker.m */, + 17D41E581D7EE0CA0031415E /* RCTBEEPickerManager.h */, + 17D41E5A1D7EE0CA0031415E /* RCTBEEPickerManager.m */, + ); + path = RCTBEEPickerManager; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 17D41E541D7EE0CA0031415E /* RCTBEEPickerManager */ = { + isa = PBXNativeTarget; + buildConfigurationList = 17D41E5E1D7EE0CA0031415E /* Build configuration list for PBXNativeTarget "RCTBEEPickerManager" */; + buildPhases = ( + 17D41E511D7EE0CA0031415E /* Sources */, + 17D41E521D7EE0CA0031415E /* Frameworks */, + 17D41E531D7EE0CA0031415E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RCTBEEPickerManager; + productName = RCTBEEPickerManager; + productReference = 17D41E551D7EE0CA0031415E /* libRCTBEEPickerManager.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 17D41E4D1D7EE0CA0031415E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "MFHJ-DZ-001-417"; + TargetAttributes = { + 17D41E541D7EE0CA0031415E = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = 17D41E501D7EE0CA0031415E /* Build configuration list for PBXProject "RCTBEEPickerManager" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 17D41E4C1D7EE0CA0031415E; + productRefGroup = 17D41E561D7EE0CA0031415E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 17D41E541D7EE0CA0031415E /* RCTBEEPickerManager */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 17D41E511D7EE0CA0031415E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 17D41E5B1D7EE0CA0031415E /* RCTBEEPickerManager.m in Sources */, + 17D41E631D7EE0EE0031415E /* BzwPicker.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 17D41E5C1D7EE0CA0031415E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 17D41E5D1D7EE0CA0031415E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 17D41E5F1D7EE0CA0031415E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../react-native/React/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 17D41E601D7EE0CA0031415E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../react-native/React/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 17D41E501D7EE0CA0031415E /* Build configuration list for PBXProject "RCTBEEPickerManager" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 17D41E5C1D7EE0CA0031415E /* Debug */, + 17D41E5D1D7EE0CA0031415E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 17D41E5E1D7EE0CA0031415E /* Build configuration list for PBXNativeTarget "RCTBEEPickerManager" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 17D41E5F1D7EE0CA0031415E /* Debug */, + 17D41E601D7EE0CA0031415E /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 17D41E4D1D7EE0CA0031415E /* Project object */; +} diff --git a/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000000000000000000000000000000..0d9f65d758caa242119cc8cac0023996c5af8411 --- /dev/null +++ b/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/xcuserdata/mfhj-dz-001-417.xcuserdatad/UserInterfaceState.xcuserstate b/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/xcuserdata/mfhj-dz-001-417.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..e9a5be8a5a67f859432f89711b973c07bdb729a8 Binary files /dev/null and b/ios/RCTBEEPickerManager.xcodeproj/project.xcworkspace/xcuserdata/mfhj-dz-001-417.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/RCTBEEPickerManager.xcscheme b/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/RCTBEEPickerManager.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..b3bafafc65a64566a46c6096540dbc1cf06876b1 --- /dev/null +++ b/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/RCTBEEPickerManager.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000000000000000000000000000000000000..abbb76cb3d50cd8b1c3445db823541aef0d0a5b3 --- /dev/null +++ b/ios/RCTBEEPickerManager.xcodeproj/xcuserdata/mfhj-dz-001-417.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + RCTBEEPickerManager.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 17D41E541D7EE0CA0031415E + + primary + + + + + diff --git a/ios/RCTBEEPickerManager/BzwPicker.h b/ios/RCTBEEPickerManager/BzwPicker.h new file mode 100755 index 0000000000000000000000000000000000000000..371165b4533c09747397eb1c754859bd5644af2c --- /dev/null +++ b/ios/RCTBEEPickerManager/BzwPicker.h @@ -0,0 +1,64 @@ +// +// BzwPicker.h +// PickerView +// +// Created by Bao on 15/12/14. +// Copyright © 2015年 Microlink. All rights reserved. +// + +#import + +#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width) +#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height) + + +typedef void(^backBolock)(NSDictionary * ); + +@interface BzwPicker : UIView + +@property (strong,nonatomic)UIPickerView *pick; + +@property(nonatomic,copy)backBolock bolock; + +@property (strong, nonatomic) NSDictionary *pickerDic;//一开始进来的字典 + +@property (strong, nonatomic) NSArray *provinceArray;//省、市 +@property (strong, nonatomic) NSArray *cityArray;//市,县 +@property (strong, nonatomic) NSArray *townArray;//县,区 + + +@property (strong, nonatomic) NSDictionary *selectedDic;//3级联动时候用到的 +@property (strong,nonatomic)NSArray *selectArry;//2级联动时候用的 + +@property (strong,nonatomic)UIButton *leftBtn;//取消 +@property (strong,nonatomic)UIButton *rightBtn; + +@property(strong,nonatomic)NSString *leftStr; +@property(strong,nonatomic)NSString *centStr; +@property(strong,nonatomic)NSString *rightStr; + + +//用来判断进来的类型 +@property(strong,nonatomic)id value; + +@property(assign,nonatomic)BOOL Correlation;//判断有没有没有关联 + +@property(nonatomic,strong)NSString *numberCorrela;//关联是2行 还是3行 + +@property(nonatomic,strong)NSArray *noCorreArry; + +//创建一个数组来传递返回的值 +@property(nonatomic,strong)NSMutableArray *backArry; + +@property(assign,nonatomic)BOOL noArryElementBool; + +//创建一个数组 接收进来的选择Value + +@property(strong,nonatomic)NSArray *selectValueArry; + + + +-(instancetype)initWithFrame:(CGRect)frame dic:(NSDictionary *)dic leftStr:(NSString *)leftStr centerStr:(NSString *)centerStr rightStr:(NSString *)rightStr topbgColor:(NSArray *)topbgColor bottombgColor:(NSArray *)bottombgColor leftbtnbgColor:(NSArray *)leftbtnbgColor rightbtnbgColor:(NSArray *)rightbtnbgColor centerbtnColor:(NSArray *)centerbtnColor selectValueArry:(NSArray *)selectValueArry; + + +@end diff --git a/ios/RCTBEEPickerManager/BzwPicker.m b/ios/RCTBEEPickerManager/BzwPicker.m new file mode 100755 index 0000000000000000000000000000000000000000..34ac20e9f7e9afed7a84bee32699157ace219307 --- /dev/null +++ b/ios/RCTBEEPickerManager/BzwPicker.m @@ -0,0 +1,715 @@ +// +// BzwPicker.m +// PickerView +// +// Created by Bao on 15/12/14. +// Copyright © 2015年 Microlink. All rights reserved. +// + +#import "BzwPicker.h" + +@implementation BzwPicker + +-(instancetype)initWithFrame:(CGRect)frame dic:(NSDictionary *)dic leftStr:(NSString *)leftStr centerStr:(NSString *)centerStr rightStr:(NSString *)rightStr topbgColor:(NSArray *)topbgColor bottombgColor:(NSArray *)bottombgColor leftbtnbgColor:(NSArray *)leftbtnbgColor rightbtnbgColor:(NSArray *)rightbtnbgColor centerbtnColor:(NSArray *)centerbtnColor selectValueArry:(NSArray *)selectValueArry +{ + self = [super initWithFrame:frame]; + if (self) + { + self.backArry=[[NSMutableArray alloc]init]; + self.selectValueArry=selectValueArry; + self.pickerDic=dic; + self.leftStr=leftStr; + self.rightStr=rightStr; + self.centStr=centerStr; + [self getStyle]; + [self getnumStyle]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self makeuiWith:topbgColor With:bottombgColor With:leftbtnbgColor With:rightbtnbgColor With:centerbtnColor]; + [self selectRow]; + }); + } + return self; +} +-(void)makeuiWith:(NSArray *)topbgColor With:(NSArray *)bottombgColor With:(NSArray *)leftbtnbgColor With:(NSArray *)rightbtnbgColor With:(NSArray *)centerbtnColor +{ + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.frame.size.width, 40)]; + view.backgroundColor = [UIColor cyanColor]; + + [self addSubview:view]; + + + self.leftBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + self.leftBtn.frame = CGRectMake(10, 5, 50, 30); + [self.leftBtn setTitle:self.leftStr forState:UIControlStateNormal]; + [self.leftBtn setFont:[UIFont systemFontOfSize:16]]; + self.leftBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + [self.leftBtn addTarget:self action:@selector(cancleAction) forControlEvents:UIControlEventTouchUpInside]; + + [self.leftBtn setTitleColor:[self colorWith:leftbtnbgColor] forState:UIControlStateNormal]; + + [view addSubview:self.leftBtn]; + + view.backgroundColor=[self colorWith:topbgColor]; + + + self.rightBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + self.rightBtn.frame = CGRectMake(view.frame.size.width-60,5, 50, 30); + [self.rightBtn setTitle:self.rightStr forState:UIControlStateNormal]; + self.rightBtn.contentHorizontalAlignment=UIControlContentHorizontalAlignmentRight; + + [self.rightBtn setTitleColor:[self colorWith:rightbtnbgColor] forState:UIControlStateNormal]; + + + [view addSubview:self.rightBtn]; + [self.rightBtn setFont:[UIFont systemFontOfSize:16]]; + [self.rightBtn addTarget:self action:@selector(cfirmAction) forControlEvents:UIControlEventTouchUpInside]; + + + UILabel *cenLabel=[[UILabel alloc]initWithFrame:CGRectMake(view.frame.size.width/2-25, 5, 50, 30)]; + + [cenLabel setFont:[UIFont systemFontOfSize:16]]; + + cenLabel.text=self.centStr; + + [cenLabel setTextColor:[self colorWith:centerbtnColor]]; + + [view addSubview:cenLabel]; + + self.pick = [[UIPickerView alloc] initWithFrame:CGRectMake(-15, 40, self.frame.size.width+15, self.frame.size.height - 40)]; + + self.pick.delegate = self; + self.pick.dataSource = self; + self.pick.showsSelectionIndicator=YES; + [self addSubview:self.pick]; + + self.pick.backgroundColor=[self colorWith:bottombgColor]; + + if (_Correlation) { + + NSDictionary *dic=(NSDictionary *)self.value; + + self.selectedDic =[dic objectForKey:[self.provinceArray objectAtIndex:0]]; + } +} +//返回显示的列数 +-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + if (_Correlation) { + //这里是关联的 + if ([_numberCorrela isEqualToString:@"three"]) { + + return 3; + + }else if ([_numberCorrela isEqualToString:@"two"]){ + + return 2; + } + + } + //这里是不关联的 + if (_noArryElementBool) { + + return 1; + + }else{ + + return self.noCorreArry.count; + } +} +//返回当前列显示的行数 +-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + if (_Correlation) { + + if (component == 0) { + + return self.provinceArray.count; + + } else if (component == 1) { + + return self.cityArray.count; + + } else { + + return self.townArray.count; + } + } + + NSLog(@"%@",[self.noCorreArry objectAtIndex:component]); + + if (self.noCorreArry.count==1) { + + return [self.noCorreArry count]; + + }else + { + + if (_noArryElementBool) { + + return [self.noCorreArry count]; + + } + + return [[self.noCorreArry objectAtIndex:component] count]; + } + +} + +#pragma mark Picker Delegate Methods + +//返回当前行的内容,此处是将数组中数值添加到滚动的那个显示栏上 +-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + if (_Correlation) { + + if (component == 0) { + + return [NSString stringWithFormat:@"%@",[self.provinceArray objectAtIndex:row]]; + + } else if (component == 1) { + + return [NSString stringWithFormat:@"%@",[self.cityArray objectAtIndex:row]]; + } else { + + return [NSString stringWithFormat:@"%@",[self.townArray objectAtIndex:row]]; + } + }else{ + + if (_noArryElementBool) { + + return [NSString stringWithFormat:@"%@",[self.noCorreArry objectAtIndex:row]]; + + }else{ + return [NSString stringWithFormat:@"%@",[[self.noCorreArry objectAtIndex:component] objectAtIndex:row]]; + } + } + +} +- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component { + + if (_Correlation) { + return 110; + }else{ + if (_noArryElementBool) { + //表示一个数组 特殊情况 + return 110; + }else{ + NSArray *arry=(NSArray *)self.value; + + return SCREEN_WIDTH/arry.count; + } + } +} + +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { + + [self.backArry removeAllObjects]; + + if (_Correlation) { + //这里是关联的 + if ([_numberCorrela isEqualToString:@"three"]) { + + + if (component == 0) + { + NSDictionary *dic=(NSDictionary *)self.value; + + NSInteger setline=[_pick selectedRowInComponent:0]; + + if (setline) { + self.selectedDic =[dic objectForKey:[self.provinceArray objectAtIndex:setline]]; + }else{ + self.selectedDic =[dic objectForKey:[self.provinceArray objectAtIndex:row]]; + } + + if (self.selectedDic) { + + self.cityArray = [self.selectedDic allKeys]; + } + else + { + self.cityArray = nil; + } + if (self.cityArray.count > 0) + { + + NSInteger oldrow=[self.pick selectedRowInComponent:1]; + + if (oldrow) { + + self.townArray=[self.selectedDic objectForKey:[self.cityArray objectAtIndex:oldrow]]; + }else{ + + row=0; + + self.townArray=[self.selectedDic objectForKey:[self.cityArray objectAtIndex:row]]; + } + } + else + { + self.townArray = nil; + } + } + + [pickerView selectedRowInComponent:1]; + [pickerView reloadAllComponents]; + [pickerView selectedRowInComponent:2]; + + if (component == 1) + { + + if (self.selectedDic && self.cityArray.count > 0) + { + + self.townArray=[self.selectedDic objectForKey:[self.cityArray objectAtIndex:row]]; + } + else + { + self.townArray = nil; + + } + [pickerView selectRow:1 inComponent:2 animated:YES]; + } + + [pickerView reloadComponent:2]; + + }else if ([_numberCorrela isEqualToString:@"two"]){ + + if (component == 0) + { + NSDictionary *dic=(NSDictionary *)self.value; + + self.selectArry =[dic objectForKey:[self.provinceArray objectAtIndex:row]]; + + if (self.selectArry.count>0) { + + self.cityArray = self.selectArry; + } + else + { + self.cityArray = nil; + } + } + + [pickerView selectedRowInComponent:1]; + [pickerView reloadComponent:1]; + } + } + //返回选择的值就可以了 + + if (_Correlation) { + + //有关联的,里面有分两种情况 + if ([_numberCorrela isEqualToString:@"three"]) { + NSString *a=[self.provinceArray objectAtIndex:[self.pick selectedRowInComponent:0]]; + NSString *b=[self.cityArray objectAtIndex:[self.pick selectedRowInComponent:1]]; + NSString *c=[self.townArray objectAtIndex:[self.pick selectedRowInComponent:2]]; + + [self.backArry addObject:a]; + [self.backArry addObject:b]; + [self.backArry addObject:c]; + + }else if ([_numberCorrela isEqualToString:@"two"]){ + + NSString *a=[self.provinceArray objectAtIndex:[self.pick selectedRowInComponent:0]]; + NSString *b=[self.cityArray objectAtIndex:[self.pick selectedRowInComponent:1]]; + NSLog(@"%@---%@",a,b); + [self.backArry addObject:a]; + [self.backArry addObject:b]; + } + + }else + { + if (_noArryElementBool) { + + [self.backArry addObject:[self.noCorreArry objectAtIndex:row]]; + + }else{ + //无关联的,直接给三个选项就行 + for (NSInteger i=0; i 0) { + + self.cityArray = [[dic objectForKey:[self.provinceArray objectAtIndex:0]] allKeys]; + } + if (self.cityArray.count > 0) { + + self.townArray = [[dic objectForKey:[self.provinceArray objectAtIndex:0]] objectForKey:[self.cityArray objectAtIndex:0]]; + + } + }else if ([_numberCorrela isEqualToString:@"two"]){ + + NSDictionary *dic=(NSDictionary *)self.value; + + self.provinceArray = [dic allKeys]; + + self.cityArray=[dic objectForKey:[self.provinceArray objectAtIndex:0]]; + } + }else + { + //这里是不关联的 + self.noCorreArry=(NSArray *)self.value; + id noArryElement=[self.noCorreArry firstObject]; + + if ([noArryElement isKindOfClass:[NSArray class]]) { + + _noArryElementBool=NO; + + }else{ + + _noArryElementBool=YES; + } + } +} + +//按了取消按钮 +-(void)cancleAction +{ + NSMutableDictionary *dic=[[NSMutableDictionary alloc]init]; + + if (self.backArry.count>0) { + [dic setValue:self.backArry forKey:@"selectedValue"]; + [dic setValue:@"cancel" forKey:@"type"]; + + self.bolock(dic); + }else{ + [self getNOselectinfo]; + + [dic setValue:self.backArry forKey:@"selectedValue"]; + [dic setValue:@"cancel" forKey:@"type"]; + + self.bolock(dic); + } + + + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:.2f animations:^{ + + [self setFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, 250)]; + + }]; + }); +} +//按了确定按钮 +-(void)cfirmAction +{ + NSMutableDictionary *dic=[[NSMutableDictionary alloc]init]; + + if (self.backArry.count>0) { + + [dic setValue:self.backArry forKey:@"selectedValue"]; + [dic setValue:@"confirm" forKey:@"type"]; + + self.bolock(dic); + + }else{ + [self getNOselectinfo]; + [dic setValue:self.backArry forKey:@"selectedValue"]; + [dic setValue:@"confirm" forKey:@"type"]; + + self.bolock(dic); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:.2f animations:^{ + + [self setFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, 250)]; + }]; + }); +} +-(void)selectRow +{ + if (_Correlation) { + //关联的一开始的默认选择行数 + + NSDictionary *dic=(NSDictionary *)self.value; + + if ([_numberCorrela isEqualToString:@"three"]) { + [self selectValueThree:dic]; + }else if ([_numberCorrela isEqualToString:@"two"]){ + + [self selectValueTwo:dic]; + } + }else{ + //一行的时候 + [self selectValueOne]; + } +} +//三行时候的选择哪个的逻辑 +-(void)selectValueThree:(NSDictionary *)dic +{ + NSString *selectStr=[NSString stringWithFormat:@"%@",self.selectValueArry.firstObject]; + + for (NSInteger i=0; i0) { + self.cityArray=selecityAry; + + } + NSString *selectStrTwo; + + if (self.selectValueArry.count>1) { + selectStrTwo=[NSString stringWithFormat:@"%@",self.selectValueArry[1]]; + } + for (NSInteger i=0; i1) { + + NSArray *arry =[threeDic objectForKey:[self.selectValueArry objectAtIndex:1]]; + if (arry.count>0) { + self.townArray=arry; + + } + } + } + + NSString *selectStrThree; + + if (self.selectValueArry.count>2) { + selectStrThree=[NSString stringWithFormat:@"%@",self.selectValueArry[2]]; + } + for (NSInteger i=0; i1) { + selectTwoStr =[NSString stringWithFormat:@"%@",[self.selectValueArry objectAtIndex:1]]; + } + + for (NSInteger i=0; i0) { + + selectStr=[NSString stringWithFormat:@"%@",[self.selectValueArry firstObject]]; + } + for (NSInteger i=0; i0) { + + if (self.selectValueArry.count>self.noCorreArry.count) { + + for (NSInteger i=0; i0) { + NSString *selectStr=[NSString stringWithFormat:@"%@",[self.selectValueArry firstObject]]; + [self.backArry addObject:selectStr]; + }else{ + + [self.backArry addObject:[self.noCorreArry objectAtIndex:0]]; + } + + }else{ + //无关联的,直接给三个选项就行 + for (NSInteger i=0; i +#import "RCTBridgeModule.h" + +@interface RCTBEEPickerManager : NSObject + +@end diff --git a/ios/RCTBEEPickerManager/RCTBEEPickerManager.m b/ios/RCTBEEPickerManager/RCTBEEPickerManager.m new file mode 100644 index 0000000000000000000000000000000000000000..b2d5307b02bea07edbdeb032fd765a457531c412 --- /dev/null +++ b/ios/RCTBEEPickerManager/RCTBEEPickerManager.m @@ -0,0 +1,146 @@ +// +// RCTBEEPickerManager.m +// RCTBEEPickerManager +// +// Created by MFHJ-DZ-001-417 on 16/9/6. +// Copyright © 2016年 MFHJ-DZ-001-417. All rights reserved. +// + +#import "RCTBEEPickerManager.h" +#import "BzwPicker.h" +#import "RCTEventDispatcher.h" + +@interface RCTBEEPickerManager() + +@property(nonatomic,strong)BzwPicker *pick; + +@end + +@implementation RCTBEEPickerManager + +@synthesize bridge = _bridge; + +RCT_EXPORT_MODULE(); + +RCT_EXPORT_METHOD(_init:(NSDictionary *)indic){ + + UIViewController *result = nil; + + UIWindow * window = [[UIApplication sharedApplication] keyWindow]; + if (window.windowLevel != UIWindowLevelNormal) + { + NSArray *windows = [[UIApplication sharedApplication] windows]; + for(UIWindow * tmpWin in windows) + { + if (tmpWin.windowLevel == UIWindowLevelNormal) + { + window = tmpWin; + break; + } + } + } + + UIView *frontView = [[window subviews] objectAtIndex:0]; + id nextResponder = [frontView nextResponder]; + + if ([nextResponder isKindOfClass:[UIViewController class]]) + + result = nextResponder; + + else + + result = window.rootViewController; + + NSString *pickerConfirmBtnText=indic[@"pickerConfirmBtnText"]; + NSString *pickerCancelBtnText=indic[@"pickerCancelBtnText"]; + NSString *pickerTitleText=indic[@"pickerTitleText"]; + NSArray *pickerConfirmBtnColor=indic[@"pickerConfirmBtnColor"]; + NSArray *pickerCancelBtnColor=indic[@"pickerCancelBtnColor"]; + NSArray *pickerTitleColor=indic[@"pickerTitleColor"]; + NSArray *pickerToolBarBg=indic[@"pickerToolBarBg"]; + NSArray *pickerBg=indic[@"pickerBg"]; + NSArray *selectArry=indic[@"selectedValue"]; + + id pickerData=indic[@"pickerData"]; + + NSMutableDictionary *dataDic=[[NSMutableDictionary alloc]init]; + + dataDic[@"pickerData"]=pickerData; + + [result.view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + + if ([obj isKindOfClass:[BzwPicker class]]) { + dispatch_async(dispatch_get_main_queue(), ^{ + + [obj removeFromSuperview]; + }); + } + + }]; + + self.pick=[[BzwPicker alloc]initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, 250) dic:dataDic leftStr:pickerCancelBtnText centerStr:pickerTitleText rightStr:pickerConfirmBtnText topbgColor:pickerToolBarBg bottombgColor:pickerBg leftbtnbgColor:pickerCancelBtnColor rightbtnbgColor:pickerConfirmBtnColor centerbtnColor:pickerTitleColor selectValueArry:selectArry]; + + _pick.bolock=^(NSDictionary *backinfoArry){ + + dispatch_async(dispatch_get_main_queue(), ^{ + + [self.bridge.eventDispatcher sendAppEventWithName:@"pickerEvent" body:backinfoArry]; + }); + }; + + dispatch_async(dispatch_get_main_queue(), ^{ + + [result.view addSubview:_pick]; + + [UIView animateWithDuration:.3 animations:^{ + + [_pick setFrame:CGRectMake(0, SCREEN_HEIGHT-250, SCREEN_WIDTH, 250)]; + + }]; + + }); + +} + +RCT_EXPORT_METHOD(show){ + if (self.pick) { + + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:.3 animations:^{ + + [_pick setFrame:CGRectMake(0, SCREEN_HEIGHT-250, SCREEN_WIDTH, 250)]; + + }]; + }); + }return; +} + +RCT_EXPORT_METHOD(hide){ + + if (self.pick) { + dispatch_async(dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:.3 animations:^{ + [_pick setFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, 250)]; + }]; + }); + }return; +} +RCT_EXPORT_METHOD(isPickerShow:(RCTResponseSenderBlock)getBack){ + + if (self.pick) { + + CGFloat pickY=_pick.frame.origin.y; + + if (pickY==SCREEN_HEIGHT) { + + getBack(@[@YES]); + }else + { + getBack(@[@NO]); + } + }else{ + getBack(@[@"picker不存在"]); + } +} + +@end diff --git a/package.json b/package.json index b843ab8585dcf0db837995587fe32a6f9b01d510..6ad6796a92562995a380c873ea41d4ad93ca7fdf 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,15 @@ { "name": "react-native-picker", - "version": "3.0.5", - "description": "react-native-picker", + "version": "4.0.0", + "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", - "url": "git+https://github.com/beefe/react-native-picker.git" + "url": "git@github.com:beefe/react-native-picker.git" }, - "keywords": [ - "react-native", - "picker" - ], - "author": { - "name": "zooble", - "email": "wenliang.web@gmail.com" - }, - "dependencies": { - "react-native-picker-android": "~1.0.3" - }, - "engines": { - "node": ">=4" - }, - "license": "ISC", - "bugs": { - "url": "https://github.com/beefe/react-native-picker/issues" - }, - "homepage": "https://github.com/beefe/react-native-picker#readme" -} \ No newline at end of file + "author": "zooble", + "license": "MIT" +}