androidscrollandroid-custom-viewonfling

Scroller.fling() isn't working as expected


This is code I'm using to receive touch events, and feed them into x,y that my canvas is using for translation :

VelocityTracker mVelocity;
Scroller scroller;

@Override
public boolean onTouchEvent(MotionEvent event) { //On touch
    super.onTouchEvent(event);

    mVelocity = VelocityTracker.obtain();
    mVelocity.addMovement(event);

    //Log.d("VELOCITY","("+mVelocity.getXVelocity()+","+mVelocity.getYVelocity()+")");

    if(event.getActionMasked()==MotionEvent.ACTION_MOVE){ //If it's a drag, call scrollMove
        mVelocity.computeCurrentVelocity(1);
        scrollMove();
    }

    if(event.getActionMasked()==MotionEvent.ACTION_UP) { //or scrollFling
        mVelocity.computeCurrentVelocity(1);
        scrollFling();
    }

    mVelocity.recycle();

    return true;
}

void scrollMove(){ //Canvas is constantly translating by (scrollMove.x,scrollMove.y) every time invalidate() is called
    scrollMove.x += mVelocity.getXVelocity() * 10f;
    scrollMove.y += mVelocity.getYVelocity() * 10f;
    invalidate();
}

void scrollFling(){ //how does scroller.fling work?
    scroller.fling(getScrollX(),getScrollY(),(int)-mVelocity.getXVelocity(),(int)-mVelocity.getYVelocity(),0,0,10000,10000);
    invalidate();
}


@Override
public void computeScroll() {
    super.computeScroll();
    if(!scroller.isFinished()){
        scroller.computeScrollOffset();
        scrollMove.x += scroller.getCurrX();
        scrollMove.y += scroller.getCurrY();
        //postInvalidateOnAnimation();
        postInvalidateOnAnimation(); //Alternated between all 3 of these
        postInvalidate(); //??
        invalidate(); //??
        Log.d("FLING","Should be flinging"); //This is only called once
    }
}

Link to a video of behavior

So scrolling is working as I would expect it to be, but flinging is not. While the scroll method is constantly getting called to return values and translate the canvas, fling is only called once, and returns whatever max value i put into the function call.

I thought scroller.fling / computeScroll was a recursive callback every frame, and as long as the fling isn't over, I'm going to receive information on where to translate my view? What am I doing wrong?


Solution

  • (thanks to @Roughy from irc.freenode/android-dev)

    The first problem here is that you're passing the wrong values to .fling()

        scroller.fling(startX, startY, velX, velY, minX, MAXX, MINY, MAXY);
    

    You flipped the min/max around.

    The second issue is that you're calling mVelocity = VelocityTracker.obtain(); every time you have a movement event change, which creates a new velocity tracker for every movement frame, you should call it only once on MotionEvent.ACTION_DOWN, and then call mVelocity.addMovement(event); on ACTION_MOVE, and ACTION_UP.

    Call mVelocity.recycle(); on ACTION_UP too.