smooth horizontal scrolling in webview - android

I have a wevbiew with a number of 'pages' (columns of text) in it, and want to be able to scroll horizontally between columns in response to Fling gestures. I can do this fine using scrollTo(), but that is rather sudden and I'd really like to be able to do a smooth transition from one 'page' to the next.
The problem as I see it: you can't attach a Scroller to a WebView, and shouldn't nest a WebView in a ScrollView.
Does anyone have any good ideas for implementing smooth or animated horizontal scrolling in a WebView?
Edited to add: I'm trying to implement an idea of knotmanish's where I use an unattached Scroller to compute the distance..
// vx and vy are from the onfling event of the gesture detector
scroller.fling(page*x, 0, vx, vy, page*(x + 1), page*(x + 1), 0, 0);
while(scroller.computeScrollOffset()){
webview.scrollTo(scroller.getCurrX(), 0);
webview.invalidate();
}
... but the while loop seems too slow to capture the scroller's movement, or something, because the behavior looks just like the scrollTo() method (the view jump to the end of the scroll).

You cannot attach a scroller to a webview however you can make use of the gesture to do the same.
The gesture detects the fling using this method
onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
Give the velocityX, velocityY to the scoller method along with other parameters
fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY)
scan the computeScrollOffset() value to find the getCurrX(),getCurrY() positions.
Extend the webview and override the methods onTouchEvent(MotionEvent ev), dispatchTouchEvent(MotionEvent ev) to return false so that by default the touch events are not consumed by the webview itself.
Now implement the gestureListener and override the onfling method mentioned above.
pass the velocity and other parameters to the scroller.
Start a loop to scan the computeScrollOffset() value to find the getCurrX() and getCurrY() and invalidate the view each time.
Pass this value to scroll the webview as needed.
Please let me know in case you need anything.

Related

Custom RecyclerView LayoutManager does not fling (smoothly)

I am working on an application which looks somewhat like this:
The RecyclerView uses a custom LayoutManager with a custom implementation of "scrollVerticallyBy"
First of. The recyclerview scroll butter smooth and renders in way less than the required 16 ms. I think I can max i out around 5 ms on a Nexus 5.
However, I also want to be able to scroll the RecyclerView from touching the View above it (it's a RelativeLayout).
Here is the problem:
1) If I just forward the onTouchEvents the scrolling is butter smooth. However, RecyclerView.fling(...) is never invoked and scrolling only works as long as the finger is touching the screen. No flinging which feels very awkward.
#Override
public boolean onTouchEvent(MotionEvent event) {
return mRecyclerView.onTouchEvent(event);
}
2) If I override .fling(...) in the RecyclerView I can get "flinging" to work by using a Scroller. This works, but does cause some strange large lags.
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mScroller.computeScrollOffset()) {
Log.d("RecyclerView", "(ondraw) Y: " + mScroller.getCurrY());
scrollBy(0, mScroller.getCurrY()- mLastY);
mLastY = mScroller.getCurrY();
postInvalidateDelayed(16); // 60 Hz
}
}
#Override
public boolean fling(int velocityX, int velocityY) {
mLastY = 0;
mScroller.fling(0, 0, velocityX, velocityY, 0, 0, -10000 ,10000);
return true;
}
I am unsure what the correct way to do this is. I feels like that if I am not overriding .fling() and force my app to repeatedly call scrollBy() by using the Scroller the scrolling is working differently.
I suspect this may have something to do with "startSmoothScroll" and "smoothScrollToPosition" which I have not overwritten. I honestly don't know what smoothscrolling is but it sounds relevant to this problem :)

How to move view using gesture detector and animation

I have added one view in linear layout and I want to move that view at run time in the direction user pushed it, for that I have added onTouchListner on view, as well as I have defined one gesture detector.
On gestureDetector's onFling method I have started translation animation on view
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
mX = e2.getX();
mY = e2.getY();
TranslateAnimation transA = new TranslateAnimation(
e1.getX(),e2.getX(),e1.getY(),e2.getY());
transA.setDuration(1000);
transA.setAnimationListener(MainActivity.this);
mBtn.startAnimation(transA);
return super.onFling(e1, e2, velocityX, velocityY);
}
translation animation works well but after animation view remains on its original position. To move view to destination location I am setting views x & y property to mX and mY
#Override
public void onAnimationEnd(Animation animation) {
mBtn.setX(mX);
mBtn.setY(mY);
}
but this is not working properly. please help, If there is any other way to achieve this please let me know.
Is there a button that is moving in there as well? I see a mBtn. Note that a view animation is only going to transform the place where a view is drawn and not where it actually is (hence a button clickable area won't move with a button). You could try doing transA.setFillAfter(true), that should stop it from going back to the original position, but I believe the clickable area will stay the same. Hence you should try doing a property animation, as it will update the properties of the view and not just where it is drawn. Doing a viewpropertyanimator might be easiest as you are animating x and y. You can read more here: http://developer.android.com/guide/topics/graphics/prop-animation.html

How can I determine motion direction in an Android Gallery?

I have been creating a Gallery derivative that uses a limited number of Views and, as such, the Adapter needs to be able to populate these Views ahead of time during a scroll or a fling. To do this, I need to get the direction of motion from the onFling(...) and onScroll(...) events.
How can I use the distanceX parameter in onScroll(...) and the velocityX parameter in onFling(...) to determine which way the Gallery is travelling, and therefore which View to prepare next?
The signs of the velocity parameters in onFling(...) and the distance parameters on onScroll(...) are opposite. In order to correctly determine which direction a Gallery is moving, the code should be as follows:
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//if distanceX is POSITIVE, the Views are travelling left
//therefore the selection position is INCREASING
return super.onScroll(e1, e2, distanceX*mVelocityFactor, distanceY*mVelocityFactor);
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//if velocityX is NEGATIVE, the Views are travelling left
//therefore the selection position is DECREASING
return super.onFling(e1, e1, velocityX*mVelocityFactor, velocityY*mVelocityFactor);
}
By the way, mVelocityFactor is just a constant I introduced to make the scroll/fling a little less energetic. I found 0.6 to be quite a nice value—it still feels intuitive to scroll but the flings are less violent.

Android Gallery Full width, no gap

I need to build something like a stream for my android app (like pulse)
I tried several horizontalListview or HorizontalScrollView but it's not smooth at all!
The smoother widget I found is the gallery.
I successfully tweaked it to right align:
http://cl.ly/0a3Q002u3H1f3w2l0g2e
My problem is when you scroll max to the right. It looks like stream #3.
Is there a way change this to avoid the gap on the right ?
Maybe to changing the maximum selectable position (# of elements - 4 in my case)
Thank you.
Actually I use this one https://github.com/vieux/Android-Horizontal-ListView
I found the problem about smoothness. The vertical listview shouldn't react when we are already scrolling a stream horizontally.
You could try something like
public class GalleryChild extends Gallery {
...
#Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (getSelectedItemPosition() >= getChildCount() - BUFFER) {
setSelection(getChildCount() - BUFFER, true);
/** Eat the event. */
return true;
} else return super.onScroll(e1, e2, distanceX, distanceY);
}

How to best handle fling gesture for Android ListActivity

I have an Android app with a ListActivity in the main view. The list contains a LinearLayout with a TextView and a hidden delete Button. The delete Button will be hidden by default. I want to use a fling gesture to show the button. I am able to detect the fling gesture thanks to question #937313 on stackoverflow. It's not clear to me how to determine which item in the list was flung, since the onTouch listener listens to the ListView. The item is not necessarily selected so getSelected* methods can't be used reliably. I am using the SimpleListAdaptor so I don't have direct access to the View Objects in the ListView.
Any ideas?
Try using AbsListView.pointToPosition() to determine the list item for the X,Y coordinate in your list view.
If you're using the recipe from #937313, you should be able to override onFling() more or less as follows:
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
Toast.makeText(listAdapter.getItem( listView.pointToPosition( (int) e1.getX(), (int) e1.getY() ).toString() );
return super.onFling();
} catch( Exception e ) {
// do nothing
}
}

Categories

Resources