Resuming a problem: send a touch event to the layout of his brother WebView, getting the same scroll as the default WebView scroll (discard)
I have a frameLayout over a WebView after this xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.app.ObservableWebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/observableWebView"> </com.app.ObservableWebView> <FrameLayout android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/frameLayout"> </FrameLayout> </RelativeLayout>
At the beginning of the application, an empty empty place for html placement is placed somewhere in the WebView Dom, and its position is set by JavascriptInterface. This position is converted with a pixel ratio, and a FrameLayout is placed above the frameLayout. When the contents of the WebView are moved, the placeholder is moved using FrameLayout (an event dispatched from an Observable WebView). So far, everything is working as it should.

In frameLayout, I need to listen for a click on it, so I installed TouchListener after this step:
private boolean mIsNativeClick = false; private float mStartNativeX; private float mStartNativeY; private final float SCROLL_THRESHOLD = 10; private void init(){ mRootFrameLayout.setOnTouchListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mStartNativeX = event.getX(); mStartNativeY = event.getY(); mIsNativeClick = true; return true; case MotionEvent.ACTION_MOVE: if (mIsNativeClick && (Math.abs(mStartNativeX - event.getX()) > SCROLL_THRESHOLD || Math.abs(mStartNativeY - event.getY()) > SCROLL_THRESHOLD)) { mIsNativeClick = false; } break; case MotionEvent.ACTION_UP: if (mIsNativeClick) {
The touch event arrives correctly for the listener, and everything works fine. Except that the WebView does not scroll when I view FrameLayout, because it is a brother of frameLayout: it is not a parent / child.
The obvious solution would be to set the return true / false correlation for View.onTouchEvent or in the listener so that Android sends the event to the next view in the three lightpad trees. But since I need to handle the up / down event in FrameLayout, starting to return true for MotionEvent.ACTION_DOWN to stop sending the next event.
Searching StackOverFlow for the past week, I have achieved a solution that works at 50%. Describe this:
Step 1: creating a WebView scroll in a FrameLayout move event
The solution consists of capturing the event on FrameLayout and setting the scroll position of the WebView according to the movement / scroll event. The problem with this solution is that the scroll fling event is not controlled (fling: when the user swipes and removes his finger from the screen, it produces an inertial effect, the scroll continues to move for several ms). Adding a reset is explained in step 2.
This is a piece of code: (part for the custom FrameLayout view)
private int movY; private float mStartNativeX; private float mStartNativeY; @Override public boolean onInterceptTouchEvent ( MotionEvent event ) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mStartNativeX = event.getX(); mStartNativeY = event.getY(); break; case MotionEvent.ACTION_SCROLL: Log.d(LOG_TAG, " scroll event"); break; } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.d(LOG_TAG, "down event : " + Float.toString(mStartNativeY)); break; case MotionEvent.ACTION_MOVE: movY = (int) ((int) mStartNativeY - event.getY()); mWebView.scrollBy(0, movY); Log.d(LOG_TAG, "move event : " + Integer.toString(movY)); return true; case MotionEvent.ACTION_UP: Log.d(LOG_TAG, "up event : "); break; default: break; } return true; }
Step 2: launch
Adding a transition to manual scrolling. It is not so easy. The main thing is to add a GestureDetector and Scroller. So I have a class that implements Runnable with a Scroller that controls the fling effect. This class is called when the GestureDetector listener is turned on.
private float mStartNativeY; private GestureDetector mGestureDetector; int movY; @Override public boolean onInterceptTouchEvent ( MotionEvent event ) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mStartNativeY = event.getY(); break; case MotionEvent.ACTION_SCROLL: Log.d(LOG_TAG, " scroll event"); break; } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { mGestureDetector.onTouchEvent(event); // 1.) remember DOWN event ALWAYS as this is important start for every gesture switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.d(LOG_TAG, "down event : " + Float.toString(mStartNativeY)); break; case MotionEvent.ACTION_MOVE: movY = (int) ((int) mStartNativeY - event.getY()); mWebView.scrollBy(0, movY); Log.d(LOG_TAG, "move event : " + Integer.toString(movY)); return true; case MotionEvent.ACTION_UP: Log.d(LOG_TAG, "up event : " + Integer.toString(mWebView.getScrollY())); return false; default: break; } return true; } // GestureDetector Listener @Override public void onLongPress(MotionEvent e) { } @Override public boolean onDown(MotionEvent e) { Log.d(LOG_TAG, "onDown"); return true; // else won't work } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float velocitX, float veloctiyY){ return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { new Flinger().start((int)velocityY); invalidate(); return true; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } private class Flinger implements Runnable { private final Scroller scroller; private int lastY = 0; Flinger() { scroller = new Scroller(getContext()); } void start(int initialVelocity) { int initialY = mWebView.getScrollY(); int maxY = Integer.MAX_VALUE; // or some appropriate max value in your code scroller.fling(0, initialY, 0, initialVelocity, 0, 10, 0, maxY); Log.i(LOG_TAG, "starting fling at " + initialY + ", velocity is " + initialVelocity + ""); lastY = initialY; mWebView.post(this); } public void run() { if (scroller.isFinished()) { Log.i(LOG_TAG, "scroller is finished, done with fling"); return; } boolean more = scroller.computeScrollOffset(); int y = scroller.getCurrY(); int diff = lastY - y; Log.d(LOG_TAG, "finger run : lasty : " + lastY +" y: " + y + " diff: "+Integer.toString(diff)); if (diff != 0) { mWebView.scrollTo(0, scroller.getCurrY()); lastY = y; } if (more) { mWebView.post(this); } } boolean isFlinging() { return !scroller.isFinished(); } void forceFinished() { if (!scroller.isFinished()) { scroller.forceFinished(true); } } }
Problem: The throw does not work every time it should. therefore, if I start throwing at a speed of 1009, the magazine says:
starting fling at 3032, velocity is 1009 up event : 3032 finger run : lasty : 3032 y: 3047 diff: -15 finger run : lasty : 3047 y: 3063 diff: -16 finger run : lasty : 3063 y: 3078 diff: -15 finger run : lasty : 3078 y: 3090 diff: -12 finger run : lasty : 3090 y: 3102 diff: -12 finger run : lasty : 3102 y: 3106 diff: -4 finger run : lasty : 3106 y: 3110 diff: -4 finger run : lasty : 3110 y: 3113 diff: -3 finger run : lasty : 3113 y: 3116 diff: -3 finger run : lasty : 3116 y: 3118 diff: -2 finger run : lasty : 3118 y: 3119 diff: -1 finger run : lasty : 3119 y: 3120 diff: -1
According to the magazine, the throw theory works, but the starting scroll point (-15) is not enough, it should be greater than ~ 100
EDIT: Alternative Solution: Posting an Event in WebView
Another explanation in the comment should be to send a MotionEvent from FrameLayout to your WebView website using
mFrameLayout.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouchEvent(MotionEvent ev) { return mWebView.onTouchEvent(MotionEvent ev); } });
The problem with this solution is that the scroll distance does not match the default WebView onTouchEvent parameter. It is too slow: the distance when it scrolls is less than it should be, and <<strong> flicker appears.
Any advice or other decision is accepted.