i'm loading a website into an android webview and i would like to improve scrolling performance. In other words i would like to make scrolling faster and smoother for the user. Any ideas?
Thanks in advance
did you declare that you want software rendering in your application's manifest (or by setting the WebView's layer type)? Maybe try hardware mode
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
I also encountered sluggish scrolling with erratic fling scrolling when embedding WebView in a fragment inside a HorizontalScrollView, but it seems to happen in other cases also. After days of trial and error, here is a solution that seems to work. The critical part is the OnTouchListener; I don't believe that the WebView settings are that important. It is counterintuitive, but you have to explicitly tell the WebView to scroll... seems like an Android bug.
WebView myWebView;
VelocityTracker mVelocityTracker;
myWebView.setOnTouchListener(new WebViewOnTouchListener());
private class WebViewOnTouchListener implements View.OnTouchListener {
float currY = 0;
float yVeloc = 0f;
WebView localWebView = myWebView;
#Override
public boolean onTouch(View v, MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch(action){
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity
// of a motion.
mVelocityTracker = VelocityTracker.obtain();
} else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(event);
currY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
yVeloc = mVelocityTracker.getYVelocity(pointerId);
float y = event.getY();
localWebView.scrollBy(0, (int) (currY - y));
currY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
localWebView.flingScroll(0, -(int)yVeloc);
break;
}
return true;
}
}
Related
I'm developing an application where I'm applying on touch listener to my layout view. I move the layout over screen but that layout doesn't respond well after 10 to 15 secs. Here is my code:
base = (LinearLayout) findViewById(R.id.load);
base.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, final MotionEvent event) {
int motion = event.getAction();
int numberOfPointers = event.getPointerCount();
if (numberOfPointers < 3) {
switch (motion & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
drag = true;
break;
case MotionEvent.ACTION_POINTER_DOWN: {
drag = false;
if (drawWaveForm != null) {
zoom = true;
}
// initial x1 and x2
BitmapDetector.prevX1 = Math.min(event.getX(0), event.getX(1));
BitmapDetector.prevX2 = Math.max(event.getX(0), event.getX(1));
BitmapDetector.prevY1 = event.getY(0);
BitmapDetector.prevY2 = event.getY(1);
}
break;
case MotionEvent.ACTION_MOVE:
if (drag && event.getActionIndex() == 0) {
// Log.d("detecting","inside the action move");
if (touching == false) {
touching = detector.isWaveformAnchor(event.getX(0), event.getY(0));
} else if (touching == true) {
float diff = event.getY(0) - loadWaveFormManager.getCh1_pos();
if ((loadWaveFormManager.getCh1_pos() + diff) < (StaticValues.screenHeight - 50)) {
int tempCh1_pos = (int) (loadWaveFormManager.getCh1_pos() + diff);
loadWaveFormManager.setCh1_pos(tempCh1_pos);
}
drawWaveForm.update(loadWaveFormManager);
}
}
break;
case MotionEvent.ACTION_UP:
// Log.d("detecting","inside the action up");
drag = false;
touching = false;
zoom = false;
break;
case MotionEvent.ACTION_POINTER_UP:
// here different function
return;
}
});
Does anyone have any idea about this? Please help me on this one.
It is not clear from your code what is your problem and when does it happen. I don't see any TimerTask or AsyncTask reference.
I guess, you're trying to do some expensive operation in UI thread, and this freezes your application. Possible long-running candidate is drawWaveForm.update(loadWaveFormManager)
If this is so, you should preform your computations asynchronously, and only then update UI.
By the way, your code will not compile at all:
public boolean onTouch(View v, final MotionEvent event)
should return true or false, instead you perform return; at the end of this method. That leads to an assumption, that you're providing irrelevant code in your question, but still want to receive a relevant answer.
Provide relevant code piece for further analyze.
Currently you are starting thread on touch event use handler instead
of thread
I am using a small square RelativeLayout as a game pad for movement in a neighboring GLSurfaceView.
I set it up so that in the onTouch method of the RelativeLayout's onTouchListenner I call a method built into the GLSurfaceView that updates the translation and rotation coordinates for my drawing.
I have everything working fine, except for the fact that touch events are only triggered if the user moves his or her finger on the RelativeLayout.
I would like it to feel a little bit like a joystick: if you leave your finger pressed on the top of the RelativeLayout, then you will keep going "up" ( or more programatically: the event.getX() and event.getY() that were sent last should get looped, or re-sent, in the GLSurfaceView until the user either moves his finger inside the RelativeLayout, or stops touching the RelativeLayout altogether.)
What should I use to detect whether or not the RelativeLayout is currently being touched (even if there is no motion in the said touch)?
Thanks!
So this is what I came up pretty much simultaneously with csmcklvey
if(event.getAction()==MotionEvent.ACTION_UP)
gM.isTouchedL = false;
else
gM.isTouchedL = true;
return true;
Where .isTouchedL is the "control boolean" I use in the GLSurfaceView
Green lit csmc's answer anyways! :)
I have used rotation animation in one of my apps, which is using the onTouchEven of view. Major function has been performed in event "ACTION_MOVE". It will help you, to get through.
public boolean onTouch(View v, MotionEvent event)
{
final float xc = volumeButton.getWidth() / 2;
final float yc = volumeButton.getHeight() / 2;
final float x = event.getX();
final float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
// volumeButton.clearAnimation();
// mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
}
case MotionEvent.ACTION_MOVE:
{
mPrevAngle = mCurrAngle;
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
animate(mPrevAngle, mCurrAngle, 100);
break;
}
case MotionEvent.ACTION_UP :
{
mPrevAngle = mCurrAngle = 0;
break;
}
}
return true;
}
You might be able to use the event.getAction() method of the MotionEvent parameter of your onTouch() method. You can check to see if it is MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP.
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//start something
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
//stop something
}
My thought is that you might be able to start or stop a thread in this manner but either way this might at least give you some more information about when the user actually presses and lifts his/her finger.
I have a ViewPager which uses GridViews for pages. I would like the ViewPager to switch pages when I swipe across the screen.
The problem is that swipes are not detected when they are made across the GridView. Outside of the GridView, the swipes work correctly; it seems that the GridView is trapping all touch events without passing it to ViewPager first.
While fiddling with the source code, I did this to a custom class extended from GridView:
#Override
public boolean onTouchEvent(MotionEvent event) {
return pager.onInterceptTouchEvent(event);
}
-- where pager refers to the ViewPager class. With this, ViewPager will correctly detect swipes and move pages accordingly, but it doesn't allow GridView to accept any events, so I can't click on the items.
What I would like to be able to do is correctly detect swipes in ViewPager and item clicks on GridView.
I had trouble with colig's implementation, but I was able to get it to work by subclassing ViewPager and overriding the onInterceptTouchEvent() method. I only checked for swipes in the X direction to allow for vertical scrolling if necessary.
private static final int minSwipeDistance = 30;
private float mTouchX;
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean response = super.onInterceptTouchEvent(event);
float x = event.getX();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mTouchX = x;
break;
case MotionEvent.ACTION_MOVE:
float dX = Math.abs(x - mTouchX);
if (dX > minSwipeDistance)
return true;
break;
}
return response;
}
Alix is on the right track. I managed to come up with this simple-looking fix. I'm not entirely sure of how it works, but it does! And for future reference, it works for other kinds of views too -- TableLayout, for example -- not just GridView.
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
downX = x;
downY = y;
return super.onInterceptTouchEvent(event);
}
case MotionEvent.ACTION_MOVE: {
deltaX = Math.abs(downX - x);
deltaY = Math.abs(downY - y);
return super.onTouchEvent(event);
}
case MotionEvent.ACTION_UP: {
if (deltaX > 4 && deltaY > 4) {
super.onTouchEvent(event);
}
}
}
return super.onInterceptTouchEvent(event);
}
You can override onInterceptTouchEvent for dispatch evenement where you want
When I try to apply a translate animation on an ImageView, the image just completely disappears. I am not sure why this would happen because I ran this code through the eclipse debugger and the value for the x_start and x_final seem to be correct.
Any ideas on why this would be happening or how I can end up getting my TranslateAnimation to work?
chargeButton.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
switch (event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
chargeButton.setLayoutParams(setPosition(x_cord, false));
break;
case MotionEvent.ACTION_UP:
int x_start = x_cord;
x_cord = 0;
slowMove(x_start, x_cord, false);
chargeButton.setLayoutParams(setPosition(x_cord, false));
break;
default:
break;
}
return true;
}
});
}
public void slowMove(int x_start, int x_final, boolean pay)
{
Animation transAnimation = new TranslateAnimation(x_start, x_final, 0, 0);
transAnimation.setFillAfter(true);
transAnimation.setDuration(1000);
if (pay)
payButton.startAnimation(transAnimation);
else
{
chargeButton.clearAnimation();
chargeButton.startAnimation(transAnimation);
}
}
A little more background, this function is being called from an onTouchListener under the MotionEvent.ACTION_UP case.
I feel as though I need to use Animation.Relative_TO_SELF or something like that for the positioning. However, I am not sure how to do that when I only have the absoute positioning of the ImageViews.
Any and all ideas will be greatly appreciated.
Do not use the layout parameters to move your views - it is really not a good idea. I have been down that road and nothing good came out of it.
Consider extending View and setup your own custom view where you can have full control of what goes on.
Is there a way in android to get the area (a collection of points) of my finger when i touch the screen. Usually, the return is one point location. I need to get the several points which can represent the area of my touching. Any one knows? Thnaks
Just use View class's onTouchEvent() or implements OnTouchListener in your activity and get the X and Y co-ordinates like,
This is View class's OnTouchEvent()..
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
float x = ev.getX();
float y = ev.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
float mLastTouchX = x;
float mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
break;
}
case MotionEvent.ACTION_CANCEL: {
break;
}
case MotionEvent.ACTION_POINTER_UP: {
break;
}
}
return true;
}
EDIT:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView textView = (TextView)findViewById(R.id.textView);
// this is the view on which you will listen for touch events
final View touchView = findViewById(R.id.touchView);
touchView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
textView.setText("Touch coordinates : " +
String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
return true;
}
});
}
For more details Android - View.
Does it have to be the real shape of the finger? Otherwise you could calculate a circle around the center of the touch.
I believe this is not possible in the touch's coordinate along with it's area. It's natively unsupported by Android API.
Ref:
http://developer.android.com/guide/topics/ui/ui-events.html
http://developer.android.com/reference/android/gesture/package-summary.html
Unfortunately not. I ran in to this a while ago - you could try normalising the data over several 'frames'. May be worth trying to figure out why you need an exact point, or set of points, and find another way of doing it.