PickerViewModule.java 18.4 KB
Newer Older
xwenliang's avatar
xwenliang committed
1 2 3
package com.beefe.picker;

import android.app.Activity;
4
import android.app.Dialog;
xwenliang's avatar
xwenliang committed
5
import android.graphics.Color;
6
import android.graphics.PixelFormat;
xwenliang's avatar
xwenliang committed
7 8 9 10
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
11
import android.view.Window;
xwenliang's avatar
xwenliang committed
12 13 14 15 16 17 18
import android.view.WindowManager;
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;
xwenliang's avatar
xwenliang committed
19
import com.beefe.picker.view.ReturnData;
xwenliang's avatar
xwenliang committed
20 21
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
xwenliang's avatar
xwenliang committed
22
import com.facebook.react.bridge.LifecycleEventListener;
xwenliang's avatar
xwenliang committed
23 24 25 26 27 28 29 30 31 32 33 34
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;

xwenliang's avatar
xwenliang committed
35 36
import static android.graphics.Color.argb;

xwenliang's avatar
xwenliang committed
37
/**
xwenliang's avatar
xwenliang committed
38
 * Author: <a href="https://github.com/shexiaoheng">heng</a>
39
 * <p>
xwenliang's avatar
xwenliang committed
40
 * Created by heng on 16/9/5.
41
 * <p>
xwenliang's avatar
xwenliang committed
42
 * Edited by heng on 16/9/22.
43 44
 * 1. PopupWindow height : full screen -> assignation
 * 2. Added pickerToolBarHeight support
45
 * <p>
46 47 48
 * Edited by heng on 2016/10/19.
 * 1. Added weights support
 * 2. Fixed return data bug
49 50 51 52 53 54 55 56 57
 * <p>
 * Edited by heng on 2016/11/16.
 * 1. Used WindowManager replace PopupWindow
 * 2. Removed method initOK() toggle() show() isPickerShow()
 * 3. Implements Application.ActivityLifecycleCallbacks
 * <p>
 * Edited by heng on 2016/11/17
 * 1. Used Dialog replace WindowManger
 * 2. Restore method show() isPickerShow()
xwenliang's avatar
xwenliang committed
58 59 60 61
 * <p>
 * Edited by heng on 2016/12/23
 * 1. Changed returnData type
 * 2. Added pickerToolBarFontSize
xwenliang's avatar
xwenliang committed
62
 * <p>
xwenliang's avatar
xwenliang committed
63 64 65 66 67 68
 * Edited by heng on 2016/12/26
 * 1. Fixed returnData bug
 * 2. Added pickerFontColor
 * 3. Added pickerFontSize
 * 4. Used LifecycleEventListener replace Application.ActivityLifecycleCallbacks
 * 5. Fixed other bug
xwenliang's avatar
xwenliang committed
69 70 71 72
 *
 * Edited by heng on 2017/01/17
 * 1. Added select(ReadableArray array, Callback callback)
 * 2. Optimization code
xwenliang's avatar
xwenliang committed
73 74
 */

xwenliang's avatar
xwenliang committed
75
public class PickerViewModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
xwenliang's avatar
xwenliang committed
76 77 78 79 80

    private static final String REACT_CLASS = "BEEPickerManager";

    private static final String PICKER_DATA = "pickerData";
    private static final String SELECTED_VALUE = "selectedValue";
81

xwenliang's avatar
xwenliang committed
82
    private static final String IS_LOOP = "isLoop";
83 84 85

    private static final String WEIGHTS = "wheelFlex";

xwenliang's avatar
xwenliang committed
86
    private static final String PICKER_BG_COLOR = "pickerBg";
87

xwenliang's avatar
xwenliang committed
88 89 90
    private static final String PICKER_TOOL_BAR_BG = "pickerToolBarBg";
    private static final String PICKER_TOOL_BAR_HEIGHT = "pickerToolBarHeight";
    private static final String PICKER_TOOL_BAR_TEXT_SIZE = "pickerToolBarFontSize";
91

xwenliang's avatar
xwenliang committed
92 93
    private static final String PICKER_CONFIRM_BTN_TEXT = "pickerConfirmBtnText";
    private static final String PICKER_CONFIRM_BTN_COLOR = "pickerConfirmBtnColor";
94

xwenliang's avatar
xwenliang committed
95 96
    private static final String PICKER_CANCEL_BTN_TEXT = "pickerCancelBtnText";
    private static final String PICKER_CANCEL_BTN_COLOR = "pickerCancelBtnColor";
97

xwenliang's avatar
xwenliang committed
98 99 100 101 102
    private static final String PICKER_TITLE_TEXT = "pickerTitleText";
    private static final String PICKER_TITLE_TEXT_COLOR = "pickerTitleColor";

    private static final String PICKER_TEXT_COLOR = "pickerFontColor";
    private static final String PICKER_TEXT_SIZE = "pickerFontSize";
xwenliang's avatar
xwenliang committed
103 104 105 106 107 108

    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";

xwenliang's avatar
xwenliang committed
109
    private static final String ERROR_NOT_INIT = "please initialize the component first";
xwenliang's avatar
xwenliang committed
110

111
    private Dialog dialog = null;
xwenliang's avatar
xwenliang committed
112 113 114 115 116 117 118

    private boolean isLoop = true;

    private String confirmText;
    private String cancelText;
    private String titleText;

119 120
    private double[] weights;

xwenliang's avatar
xwenliang committed
121
    private ArrayList<ReturnData> returnData;
xwenliang's avatar
xwenliang committed
122

123
    private int curStatus;
xwenliang's avatar
xwenliang committed
124

xwenliang's avatar
xwenliang committed
125 126 127
    private PickerViewLinkage pickerViewLinkage;
    private PickerViewAlone pickerViewAlone;

xwenliang's avatar
xwenliang committed
128 129
    public PickerViewModule(ReactApplicationContext reactContext) {
        super(reactContext);
xwenliang's avatar
xwenliang committed
130
        reactContext.addLifecycleEventListener(this);
xwenliang's avatar
xwenliang committed
131 132 133 134 135 136 137 138 139 140 141
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    @ReactMethod
    public void _init(ReadableMap options) {
        Activity activity = getCurrentActivity();
        if (activity != null && options.hasKey(PICKER_DATA)) {
142
            View view = activity.getLayoutInflater().inflate(R.layout.picker_view, null);
143 144 145 146
            RelativeLayout barLayout = (RelativeLayout) view.findViewById(R.id.barLayout);
            TextView cancelTV = (TextView) view.findViewById(R.id.cancel);
            TextView titleTV = (TextView) view.findViewById(R.id.title);
            TextView confirmTV = (TextView) view.findViewById(R.id.confirm);
147
            RelativeLayout pickerLayout = (RelativeLayout) view.findViewById(R.id.pickerLayout);
jinlongtao's avatar
jinlongtao committed
148 149
            pickerViewLinkage = (PickerViewLinkage) view.findViewById(R.id.pickerViewLinkage);
            pickerViewAlone = (PickerViewAlone) view.findViewById(R.id.pickerViewAlone);
150 151

            int barViewHeight;
xwenliang's avatar
xwenliang committed
152
            if (options.hasKey(PICKER_TOOL_BAR_HEIGHT)) {
xwenliang's avatar
xwenliang committed
153
                try {
xwenliang's avatar
xwenliang committed
154
                    barViewHeight = options.getInt(PICKER_TOOL_BAR_HEIGHT);
xwenliang's avatar
xwenliang committed
155
                } catch (Exception e) {
xwenliang's avatar
xwenliang committed
156
                    barViewHeight = (int) options.getDouble(PICKER_TOOL_BAR_HEIGHT);
xwenliang's avatar
xwenliang committed
157
                }
xwenliang's avatar
xwenliang committed
158 159 160 161 162 163 164
            } else {
                barViewHeight = (int) (activity.getResources().getDisplayMetrics().density * 40);
            }
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.MATCH_PARENT,
                    barViewHeight);
            barLayout.setLayoutParams(params);
xwenliang's avatar
xwenliang committed
165

xwenliang's avatar
xwenliang committed
166 167
            if (options.hasKey(PICKER_TOOL_BAR_BG)) {
                ReadableArray array = options.getArray(PICKER_TOOL_BAR_BG);
168
                int[] colors = getColor(array);
xwenliang's avatar
xwenliang committed
169
                barLayout.setBackgroundColor(argb(colors[3], colors[0], colors[1], colors[2]));
xwenliang's avatar
xwenliang committed
170 171
            }

xwenliang's avatar
xwenliang committed
172 173 174 175 176 177
            if (options.hasKey(PICKER_TOOL_BAR_TEXT_SIZE)) {
                int toolBarTextSize = options.getInt(PICKER_TOOL_BAR_TEXT_SIZE);
                cancelTV.setTextSize(toolBarTextSize);
                titleTV.setTextSize(toolBarTextSize);
                confirmTV.setTextSize(toolBarTextSize);
            }
xwenliang's avatar
xwenliang committed
178

xwenliang's avatar
xwenliang committed
179 180
            if (options.hasKey(PICKER_CONFIRM_BTN_TEXT)) {
                confirmText = options.getString(PICKER_CONFIRM_BTN_TEXT);
xwenliang's avatar
xwenliang committed
181 182 183
            }
            confirmTV.setText(!TextUtils.isEmpty(confirmText) ? confirmText : "");

xwenliang's avatar
xwenliang committed
184 185
            if (options.hasKey(PICKER_CONFIRM_BTN_COLOR)) {
                ReadableArray array = options.getArray(PICKER_CONFIRM_BTN_COLOR);
186
                int[] colors = getColor(array);
xwenliang's avatar
xwenliang committed
187
                confirmTV.setTextColor(argb(colors[3], colors[0], colors[1], colors[2]));
xwenliang's avatar
xwenliang committed
188 189 190 191
            }
            confirmTV.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
192
                    switch (curStatus) {
193 194 195 196 197 198 199
                        case 0:
                            returnData = pickerViewAlone.getSelectedData();
                            break;
                        case 1:
                            returnData = pickerViewLinkage.getSelectedData();
                            break;
                    }
xwenliang's avatar
xwenliang committed
200 201 202 203 204 205
                    commonEvent(EVENT_KEY_CONFIRM);
                    hide();
                }
            });


xwenliang's avatar
xwenliang committed
206 207
            if (options.hasKey(PICKER_TITLE_TEXT)) {
                titleText = options.getString(PICKER_TITLE_TEXT);
xwenliang's avatar
xwenliang committed
208 209
            }
            titleTV.setText(!TextUtils.isEmpty(titleText) ? titleText : "");
xwenliang's avatar
xwenliang committed
210 211
            if (options.hasKey(PICKER_TITLE_TEXT_COLOR)) {
                ReadableArray array = options.getArray(PICKER_TITLE_TEXT_COLOR);
212
                int[] colors = getColor(array);
xwenliang's avatar
xwenliang committed
213
                titleTV.setTextColor(argb(colors[3], colors[0], colors[1], colors[2]));
xwenliang's avatar
xwenliang committed
214 215
            }

xwenliang's avatar
xwenliang committed
216 217
            if (options.hasKey(PICKER_CANCEL_BTN_TEXT)) {
                cancelText = options.getString(PICKER_CANCEL_BTN_TEXT);
xwenliang's avatar
xwenliang committed
218 219
            }
            cancelTV.setText(!TextUtils.isEmpty(cancelText) ? cancelText : "");
xwenliang's avatar
xwenliang committed
220 221
            if (options.hasKey(PICKER_CANCEL_BTN_COLOR)) {
                ReadableArray array = options.getArray(PICKER_CANCEL_BTN_COLOR);
222
                int[] colors = getColor(array);
xwenliang's avatar
xwenliang committed
223
                cancelTV.setTextColor(argb(colors[3], colors[0], colors[1], colors[2]));
xwenliang's avatar
xwenliang committed
224 225 226 227
            }
            cancelTV.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
228
                    switch (curStatus) {
229 230 231 232 233 234 235
                        case 0:
                            returnData = pickerViewAlone.getSelectedData();
                            break;
                        case 1:
                            returnData = pickerViewLinkage.getSelectedData();
                            break;
                    }
xwenliang's avatar
xwenliang committed
236 237 238 239 240 241 242 243 244
                    commonEvent(EVENT_KEY_CANCEL);
                    hide();
                }
            });

            if (options.hasKey(IS_LOOP)) {
                isLoop = options.getBoolean(IS_LOOP);
            }

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
            if (options.hasKey(WEIGHTS)) {
                ReadableArray array = options.getArray(WEIGHTS);
                weights = new double[array.size()];
                for (int i = 0; i < array.size(); i++) {
                    switch (array.getType(i).name()) {
                        case "Number":
                            try {
                                weights[i] = array.getInt(i);
                            } catch (Exception e) {
                                weights[i] = array.getDouble(i);
                            }
                            break;
                        case "String":
                            try {
                                weights[i] = Double.parseDouble(array.getString(i));
                            } catch (Exception e) {
                                weights[i] = 1.0;
                            }
                            break;
                        default:
                            weights[i] = 1.0;
                            break;
                    }
                }
            }

xwenliang's avatar
xwenliang committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
            int pickerTextColor = 0xff000000;
            if (options.hasKey(PICKER_TEXT_COLOR)) {
                ReadableArray array = options.getArray(PICKER_TEXT_COLOR);
                int[] colors = getColor(array);
                pickerTextColor = Color.argb(colors[3], colors[0], colors[1], colors[2]);
            }

            int pickerTextSize = 16;
            if (options.hasKey(PICKER_TEXT_SIZE)) {
                try {
                    pickerTextSize = options.getInt(PICKER_TEXT_SIZE);
                } catch (Exception e) {
                    pickerTextSize = (int) options.getDouble(PICKER_TEXT_SIZE);
                }
            }

xwenliang's avatar
xwenliang committed
287 288
            ReadableArray pickerData = options.getArray(PICKER_DATA);

289
            int pickerViewHeight;
xwenliang's avatar
xwenliang committed
290 291
            String name = pickerData.getType(0).name();
            switch (name) {
xwenliang's avatar
xwenliang committed
292
                case "Map":
293
                    curStatus = 1;
xwenliang's avatar
xwenliang committed
294 295
                    pickerViewLinkage.setVisibility(View.VISIBLE);
                    pickerViewAlone.setVisibility(View.GONE);
296

297
                    pickerViewLinkage.setPickerData(pickerData, weights);
xwenliang's avatar
xwenliang committed
298 299
                    pickerViewLinkage.setTextColor(pickerTextColor);
                    pickerViewLinkage.setTextSize(pickerTextSize);
xwenliang's avatar
xwenliang committed
300
                    pickerViewLinkage.setIsLoop(isLoop);
301

xwenliang's avatar
xwenliang committed
302 303
                    pickerViewLinkage.setOnSelectListener(new OnSelectedListener() {
                        @Override
xwenliang's avatar
xwenliang committed
304
                        public void onSelected(ArrayList<ReturnData> selectedList) {
305
                            returnData = selectedList;
xwenliang's avatar
xwenliang committed
306 307 308
                            commonEvent(EVENT_KEY_SELECTED);
                        }
                    });
xwenliang's avatar
xwenliang committed
309
                    pickerViewHeight = pickerViewLinkage.getViewHeight();
xwenliang's avatar
xwenliang committed
310
                    break;
xwenliang's avatar
xwenliang committed
311
                default:
312
                    curStatus = 0;
xwenliang's avatar
xwenliang committed
313 314
                    pickerViewAlone.setVisibility(View.VISIBLE);
                    pickerViewLinkage.setVisibility(View.GONE);
xwenliang's avatar
xwenliang committed
315

316
                    pickerViewAlone.setPickerData(pickerData, weights);
xwenliang's avatar
xwenliang committed
317 318
                    pickerViewAlone.setTextColor(pickerTextColor);
                    pickerViewAlone.setTextSize(pickerTextSize);
xwenliang's avatar
xwenliang committed
319 320 321 322
                    pickerViewAlone.setIsLoop(isLoop);

                    pickerViewAlone.setOnSelectedListener(new OnSelectedListener() {
                        @Override
xwenliang's avatar
xwenliang committed
323
                        public void onSelected(ArrayList<ReturnData> selectedList) {
324
                            returnData = selectedList;
xwenliang's avatar
xwenliang committed
325 326 327 328
                            commonEvent(EVENT_KEY_SELECTED);
                        }
                    });

xwenliang's avatar
xwenliang committed
329
                    pickerViewHeight = pickerViewAlone.getViewHeight();
xwenliang's avatar
xwenliang committed
330 331 332
                    break;
            }

xwenliang's avatar
xwenliang committed
333 334 335 336 337 338
            if (options.hasKey(SELECTED_VALUE)) {
                ReadableArray array = options.getArray(SELECTED_VALUE);
                String[] selectedValue = getSelectedValue(array);
                select(selectedValue);
            }

339 340 341
            if (options.hasKey(PICKER_BG_COLOR)) {
                ReadableArray array = options.getArray(PICKER_BG_COLOR);
                int[] colors = getColor(array);
xwenliang's avatar
xwenliang committed
342
                pickerLayout.setBackgroundColor(argb(colors[3], colors[0], colors[1], colors[2]));
343 344 345 346 347 348 349 350 351 352
            }

            int height = barViewHeight + pickerViewHeight;
            if (dialog == null) {
                dialog = new Dialog(activity, R.style.Dialog_Full_Screen);
                dialog.setContentView(view);
                WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
                Window window = dialog.getWindow();
                if (window != null) {
                    layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
353
                    layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
354 355 356 357 358 359 360
                    layoutParams.format = PixelFormat.TRANSPARENT;
                    layoutParams.windowAnimations = R.style.PickerAnim;
                    layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
                    layoutParams.height = height;
                    layoutParams.gravity = Gravity.BOTTOM;
                    window.setAttributes(layoutParams);
                }
361
            } else {
362 363
                dialog.dismiss();
                dialog.setContentView(view);
xwenliang's avatar
xwenliang committed
364 365 366 367
            }
        }
    }

xwenliang's avatar
xwenliang committed
368 369 370 371 372 373 374 375 376 377 378 379
    @ReactMethod
    public void select(ReadableArray array, Callback callback) {
        if (dialog == null) {
            if (callback != null) {
                callback.invoke(ERROR_NOT_INIT);
            }
            return;
        }
        String[] selectedValue = getSelectedValue(array);
        select(selectedValue);
    }

xwenliang's avatar
xwenliang committed
380
    @ReactMethod
381 382
    public void show() {
        if (dialog == null) {
xwenliang's avatar
xwenliang committed
383 384
            return;
        }
385 386
        if (!dialog.isShowing()) {
            dialog.show();
xwenliang's avatar
xwenliang committed
387 388 389 390 391
        }
    }

    @ReactMethod
    public void hide() {
392 393 394 395 396
        if (dialog == null) {
            return;
        }
        if (dialog.isShowing()) {
            dialog.dismiss();
xwenliang's avatar
xwenliang committed
397 398 399 400 401
        }
    }

    @ReactMethod
    public void isPickerShow(Callback callback) {
xwenliang's avatar
xwenliang committed
402 403
        if (callback == null)
            return;
404
        if (dialog == null) {
xwenliang's avatar
xwenliang committed
405 406
            callback.invoke(ERROR_NOT_INIT);
        } else {
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
            callback.invoke(null, dialog.isShowing());
        }
    }

    private int[] getColor(ReadableArray array) {
        int[] colors = new int[4];
        for (int i = 0; i < array.size(); i++) {
            switch (i) {
                case 0:
                case 1:
                case 2:
                    colors[i] = array.getInt(i);
                    break;
                case 3:
                    colors[i] = (int) (array.getDouble(i) * 255);
                    break;
                default:
                    break;
            }
xwenliang's avatar
xwenliang committed
426
        }
427
        return colors;
xwenliang's avatar
xwenliang committed
428 429
    }

xwenliang's avatar
xwenliang committed
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
    private String[] getSelectedValue(ReadableArray array) {
        String[] 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;
        }
        return selectValue;
    }

    private void select(String[] selectedValue) {
        switch (curStatus) {
            case 0:
                pickerViewAlone.setSelectValue(selectedValue);
                break;
            case 1:
                pickerViewLinkage.setSelectValue(selectedValue);
                break;
        }
    }

xwenliang's avatar
xwenliang committed
465 466
    private void commonEvent(String eventKey) {
        WritableMap map = Arguments.createMap();
xwenliang's avatar
xwenliang committed
467 468 469 470 471 472
        map.putString("type", eventKey);
        WritableArray indexes = Arguments.createArray();
        WritableArray values = Arguments.createArray();
        for (ReturnData data : returnData) {
            indexes.pushInt(data.getIndex());
            values.pushString(data.getItem());
xwenliang's avatar
xwenliang committed
473
        }
xwenliang's avatar
xwenliang committed
474 475
        map.putArray("selectedValue", values);
        map.putArray("selectedIndex", indexes);
xwenliang's avatar
xwenliang committed
476 477 478 479 480 481 482 483 484 485
        sendEvent(getReactApplicationContext(), PICKER_EVENT_NAME, map);
    }

    private void sendEvent(ReactContext reactContext,
                           String eventName,
                           @Nullable WritableMap params) {
        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, params);
    }
486 487

    @Override
xwenliang's avatar
xwenliang committed
488
    public void onHostResume() {
489 490 491 492

    }

    @Override
xwenliang's avatar
xwenliang committed
493
    public void onHostPause() {
494
        hide();
xwenliang's avatar
xwenliang committed
495
        dialog = null;
496 497 498
    }

    @Override
xwenliang's avatar
xwenliang committed
499
    public void onHostDestroy() {
xwenliang's avatar
xwenliang committed
500

501
    }
xwenliang's avatar
xwenliang committed
502
}