class WXScrollView extends ScrollView implements Callback, IWXScroller,
        WXGestureObservable,NestedScrollingChild {

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if(!scrollable) {
      return true; // when scrollable is set to false, then eat the touch event
    }
    if (mRedirectTouchToStickyView) {

      if (mScrollRect == null) {
        mScrollRect = new Rect();
        getGlobalVisibleRect(mScrollRect);
      }
      mCurrentStickyView.getLocationOnScreen(stickyViewP);
      ev.offsetLocation(0, -(stickyViewP[1] - mScrollRect.top));
    }

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      mHasNotDoneActionDown = false;
    }

    if (mHasNotDoneActionDown) {
      MotionEvent down = MotionEvent.obtain(ev);
      down.setAction(MotionEvent.ACTION_DOWN);
      mHasNotDoneActionDown = false;
      down.recycle();
    }

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      ox = ev.getX();
      oy = ev.getY();
      // Dispatch touch event to parent view
      startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL | ViewCompat.SCROLL_AXIS_VERTICAL);
    }

    if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
      mHasNotDoneActionDown = true;
      // stop nested scrolling dispatch
      stopNestedScroll();
    }

    if (ev.getAction() == MotionEvent.ACTION_MOVE) {
      float clampedX = ev.getX();
      float clampedY = ev.getY();
      int dx = (int) (ox - clampedX);
      int dy = (int) (oy - clampedY);

      if (dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)) {
        // sub dx/dy was consumed by parent view!!!
        ev.setLocation(clampedX+consumed[0],clampedY+consumed[1]);
      }
      ox = ev.getX();
      oy = ev.getY();
    }

    return super.onTouchEvent(ev);
  }

  public  WXScrollView(Context context);
  public  WXScrollView(Context context, AttributeSet attrs);
  public  WXScrollView(Context context, AttributeSet attrs, int defStyle);

}