使用了一段时间的react-native,它的UI设计方式真是酷炫,原来我是学android的,由于有android的开发基础,所以我打算从java上学习react-native在原生代码上的设计,并且写下该文章笔记作为以后的知识回顾。
react-native版本 0.33.0AndroidManifest.xml
... <application android:name=".MainApplication" //使用自己的Application android:allowBackup="true" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" // 初始Activity android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize"> // 添加配置监听 <intent-filter> // 隐式intent配置 <action android:name="android.intent.action.MAIN" /> // 决定应用程序最先启动的Activity <category android:name="android.intent.category.LAUNCHER" /> // 决定应用程序是否显示在程序列表里 </intent-filter> </activity> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> // debug模式下react-native的工具Activity </application> </manifest>MainApplication.java
// ReactApplication接口定义getReactNativeHost方法 public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { // 开发者模式开关 @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; // 全局类BuildConfig,判断是否为debug模式 } // 返回ReactPackage对象数组, // ReactPackage定义基本的原生模块和视图管理 @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage() ); } }; // ReactNativeHost控制一个ReactInstanceManager对象 @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } }MainActivity继承com.facebook.react.ReactActivity,ReactActivity实现DefaultHardwareBackBtnHandler(机器返回按钮接口,触发JS中返回按钮监听事件),PermissionAwareActivity两个接口,使用ReactActivityDelegate封装主干代码的
com.facebook.react.ReactActivityDelegate
/** * MainActivity的初始化 */ public class ReactActivityDelegate { private static final String REDBOX_PERMISSION_MESSAGE = "Overlay permissions needs to be granted in order for react native apps to run in dev mode"; private final @Nullable Activity mActivity; private final @Nullable FragmentActivity mFragmentActivity; private final @Nullable String mMainComponentName; // app名 private @Nullable ReactRootView mReactRootView; // 根视图 private @Nullable DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; // 双击'R'键Reload JS private @Nullable PermissionListener mPermissionListener; ... protected void onCreate(Bundle savedInstanceState) { if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) { // Get permission to show redbox in dev builds. if (!Settings.canDrawOverlays(getContext())) { Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); getContext().startActivity(serviceIntent); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); } } if (mMainComponentName != null) { loadApp(mMainComponentName); // 创建ReactRootView } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); } ... private Context getContext() { if (mActivity != null) { return mActivity; } return Assertions.assertNotNull(mFragmentActivity); } // 返回Activity或FragmentActivity转换后的Activity private Activity getPlainActivity() { return ((Activity) getContext()); } }ReactRootView继承SizeMonitoringFrameLayout,基础父类为FrameLayout。
ReactRootView
... /** * 监听窗口大小变化改变内部布局,获取触摸事件遍历子视图触发JSTouchDispatcher中的响应事件 * 重写ViewGroup方法: * onInterceptTouchEvent * requestDisallowInterceptTouchEvent * 重写View方法: * onTouchEvent */ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView { ... /** * 获取所有的屏幕触摸事件 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { dispatchJSTouchEvent(ev); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { dispatchJSTouchEvent(ev); super.onTouchEvent(ev); // 当没有子类触发时返回true // 从而允许后续的触摸 return true; } private void dispatchJSTouchEvent(MotionEvent event) { ... // 所有事件统一通过JSTouchDispatcher发送触摸事件给JS mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher); } ... }JSTouchDispatcher
/** * 触摸事件和JS事件连接 */ public class JSTouchDispatcher { ... // 找出触发事件的视图ID public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { //MotionEvent.ACTION_POINTER_DOWN 多点按下 int action = ev.getAction() & MotionEvent.ACTION_MASK; // 获取action,添加&...支持多点触摸 if (action == MotionEvent.ACTION_DOWN) { // mTargetTag按钮事件标识符,-1为初始 if (mTargetTag != -1) { FLog.e( ReactConstants.TAG, "Got DOWN touch before receiving UP or CANCEL from last gesture"); } // 是否取消原生手势 mChildIsHandlingNativeGesture = false; // 查找触发手势的视图ID mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch( ev.getX(), ev.getY(), mRootViewGroup, mTargetCoordinates, // 储存ev的x,y null); // 处罚获取到的子类视图ID,处罚内部的JS事件 eventDispatcher.dispatchEvent( TouchEvent.obtain( mTargetTag, TouchEventType.START, // 说明是按下事件 ev, mTargetCoordinates[0], mTargetCoordinates[1], mTouchEventCoalescingKeyHelper)); } ...后面的结构基本相同,主要是通过eventDispatcher.dispatchEvent触发不同的JS事件 } ... }touch部分这里只是简单的介绍了下,详细解析可以参考React-Native系列Android——Touch事件原理及状态效果