React-Native系列Android——Touch事件原理及状态效果

本文深入探讨了React-Native在Android平台上触摸事件的处理机制,包括ReactRootView如何统一处理事件,以及如何通过EventDispatcher发送事件到JS。文章详细解释了事件的传递、拦截和处理,以及React组件如何利用Touch事件实现不同交互效果,如点击、变色和透明度变化。
摘要由CSDN通过智能技术生成

Native原生相比于HybridH5最大优点是具有流畅和复杂的交互效果,触摸事件便是其中重要一项,包括点击(Click)、长按(LongClick)、手势(gesture)等。

以最简单常见的点击(Click)为例,Native组件可以自定义selector,使得被点击的组件具有动态效果,Android 5.0以上甚至可以有涟漪效果(Material Design)。而这些在HybridH5中很难实现,很多时候区分它们与原生最简单的方法就是检验点击交互效果。

React-Native的强大之处在于实现了较为全面的Touch事件机制,虽然仍略有缺陷,但相比于HybridH5的体验而言,已经足足提高了一大截,下面分析讲解一下其实现原理,和具体使用方式。


1、Touch事件机制

如果阅读过React-Native源码的话,应该了解React-Native页面的UI根视图是ReactRootView,包路径是:com.facebook.react.ReactRootView,它是FramLayout的一个子类。

首先,来看一下ReactActivity这个页面基类,ReactRootView是如何作为React-Native的根视图被初始化及添加的。

public abstract class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
   

...

  protected ReactRootView createRootView() {
    return new ReactRootView(this);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(this)) {
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        startActivity(serviceIntent);
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      }
    }

    mReactInstanceManager = createReactInstanceManager();
    ReactRootView mReactRootView = createRootView();
    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
    setContentView(mReactRootView);
  }

...

}

ReactActivityonCreate这个生命周期里,直接实列化,然后作为当前WindowContentView,也就可以认为其是所有React-Native组件的根视图。

熟悉Android触摸事件机制的,应该知道视图树中,触摸事件是逐级传递的,每个视图(View)中有两个接收和处理Touch事件的方法,分别是onInterceptTouchEventonTouchEvent,这两个方法的区别为:

onInterceptTouchEvent的传递层级是由父视图向子视图,顾名思义,通常用作事件拦截。
onTouchEvent的传递层级是由子视图向父视图,通常用作事件处理。

我们来看一下ReactRootView的事件接收和处理。

public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
   
   ...

     @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    handleTouchEvent(ev);
    return super.onInterceptTouchEvent(ev);
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    handleTouchEvent(ev);
    super.onTouchEvent(ev);
    // In case when there is no children interested in handling touch event, we return true from
    // the root view in order to receive subsequent events related to that gesture
    return true;
  }

   ...
}

很明显,这里onInterceptTouchEventonTouchEvent的处理都是全部交给handleTouchEvent方法统一处理的。

我们再继续看一下handleTouchEvent方法。

public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
   
   ...

    /**
   * Main catalyst view is responsible for collecting and sending touch events to JS. This method
   * reacts for an incoming android native touch events ({@link MotionEvent}) and calls into
   * {@link com.facebook.react.uimanager.events.EventDispatcher} when appropriate.
   * It uses {@link com.facebook.react.uimanager.TouchTargetManagerHelper#findTouchTargetView}
   * helper method for figuring out a react view ID in the case of ACTION_DOWN
   * event (when the gesture starts).
   */
  private void handleTouchEvent(MotionEvent ev) {

   ...

   int action = ev.getAction() & MotionEvent.ACTION_MASK;
    ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
    EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
        .getEventDispatcher();
    if (action == MotionEvent.ACTION_DOWN) {

    ...

    mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
          ev.getX(),
          ev.getY(),
          this,
          mTargetCoordinates);    

    eventDispatcher.dispatchEvent(
          TouchEvent.obtain(
              mTargetTag,
              SystemClock.uptimeMillis(),
              TouchEventType.START,
              ev,
              mTargetCoordinates[0],
              mTargetCoordinates[1]));
    } else if (action == MotionEvent.ACTION_UP) {
      // End of the gesture. We reset target tag to -1 and expect no further event associated with
      
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值