Add float debug button for react native

Published on:

React-native 里面在模拟器里面可以通过快捷键打开开发菜单,在设备里面可以通过摇晃设备打开开发菜单。但是摇晃有时候并不是一个好的操作,比如是个 pad,或者比如你自己的设备本身会触发晃动动作。那么如何在开发模式下面增加一个按钮打开这个菜单呢?可惜官方对这个功能没有兴趣多做开发 https://github.com/facebook/react-native/issues/10191

iOS

ios 里面直接就把这个接口暴露出来了,可以直接在 js 里面调用。

import {NativeModules} from 'react-native';

// 在某个按钮的动作里面
const {DevMenu} = NativeModules;
DevMenu.show();

Android

iOS 是 react-native 的亲儿子,Android 里面并没有那么方便的方法,得自己通过 native 代码加。

下面两种方式加的都是 android.support.design.widget.FloatingActionButton 按钮,其它的类似。需要增加好编译依赖 compile 'com.android.support:design:23.0.0',版本号按照自己的修改下。

        private void addDevButton() {

            MainApplication application = (MainApplication) getApplication();
            ReactNativeHost reactNativeHost = application.getReactNativeHost();
            ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager();
            final DevSupportManager devSupportManager = reactInstanceManager.getDevSupportManager();

            // 这里是增加一个自定义菜单
//            devSupportManager.addCustomDevOption("Custom dev option", new DevOptionHandler() {
//                @Override
//                public void onOptionSelected() {
//                    Toast.makeText(MainActivity.this, "Hello from custom dev option", Toast.LENGTH_SHORT).show();
//                }
//            });


            // Fake empty container dev_button_layout
            // 创建一个 layout
            RelativeLayout lContainerLayout = new RelativeLayout(mActivity.getApplicationContext());
            lContainerLayout.setLayoutParams(new RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.MATCH_PARENT ));

            // custom view
            // 创建一个 button
            FloatingActionButton button = new FloatingActionButton(mActivity);
            button.setImageResource(R.drawable.ga_airplane);

            RelativeLayout.LayoutParams lButtonParams = new RelativeLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
            );
            lButtonParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            lButtonParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            button.setLayoutParams(lButtonParams);

            ViewGroup.MarginLayoutParams mp = (ViewGroup.MarginLayoutParams) button.getLayoutParams();
            mp.setMargins(0, 0, 0, dpToPx(mActivity, 125));

            button.setLayoutParams(mp);

            //设定拖动动作
            button.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getActionMasked()) {
                        case MotionEvent.ACTION_DOWN:
                            dX = v.getX() - event.getRawX();
                            dY = v.getY() - event.getRawY();
                            lastAction = MotionEvent.ACTION_DOWN;
                            break;

                        case MotionEvent.ACTION_MOVE:
                            v.setY(event.getRawY() + dY);
                            v.setX(event.getRawX() + dX);
                            lastAction = MotionEvent.ACTION_MOVE;
                            break;

                        case MotionEvent.ACTION_UP:
                            if (lastAction == MotionEvent.ACTION_DOWN)
                                // 点击的时候打开菜单
                                devSupportManager.showDevOptionsDialog();
                            break;

                        default:
                            return false;
                    }
                    return true;
                }
            });

            lContainerLayout.addView(button);
            addContentView(lContainerLayout, new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.MATCH_PARENT ));
        }

上面是纯代码方式,还可以通过 xml 文件方式搞定。

新建一个 layout 文件,取名比如叫做 dev_button_layout.xml, rootTag 是 RelativeLayout。然后在里面添加一个 FloatingActionButton,id 设置为 dev_button,然后设置好属性和位置。

        private void addDevButton() {
            MainApplication application = (MainApplication) getApplication();
            ReactNativeHost reactNativeHost = application.getReactNativeHost();
            ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager();
            final DevSupportManager devSupportManager = reactInstanceManager.getDevSupportManager();

            View view = View.inflate(mActivity, R.layout.dev_button_layout, null);
            FloatingActionButton button = (FloatingActionButton) view.findViewById(R.id.dev_button);
            //button.setImageResource(R.drawable.ga_airplane);

            button.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getActionMasked()) {
                        case MotionEvent.ACTION_DOWN:
                            dX = v.getX() - event.getRawX();
                            dY = v.getY() - event.getRawY();
                            lastAction = MotionEvent.ACTION_DOWN;
                            break;

                        case MotionEvent.ACTION_MOVE:
                            v.setY(event.getRawY() + dY);
                            v.setX(event.getRawX() + dX);
                            lastAction = MotionEvent.ACTION_MOVE;
                            break;

                        case MotionEvent.ACTION_UP:
                            if (lastAction == MotionEvent.ACTION_DOWN)
                                devSupportManager.showDevOptionsDialog();
                            break;

                        default:
                            return false;
                    }
                    return true;
                }
            });

            addContentView(view, new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.MATCH_PARENT ));
        }

然后在你的 MainActivityonCreate 里面,在 super.onCreate(savedInstanceState); 后面增加

            // debug 环境下才显示
            if(BuildConfig.DEBUG)
                addDevButton();

Comments