使用了一段时间的react-native,它的UI设计方式真是酷炫,原来我是学android的,由于有android的开发基础,所以我打算从java上学习react-native在原生代码上的设计,并且写下该文章笔记作为以后的知识回顾。
AndroidManifest.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 getPackages() {
return Arrays.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事件原理及状态效果