Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VelocityTracker giving random seeming results

To get a better understanding of how views work, I'm trying to make a RelativeLayout that I can drag around and fling. The idea is to capture onTouch events, set the layout parameters of the RelativeLayout during ACTION_MOVE, and then use a Scroller to "fling" the the view on ACTION_UP.

To track Velocity, I am using a VelocityTracker. While the view moves as expected when I drag it around, the VelocityTracker is giving seemingly random results.

Below is a log snippet of me sliding my finger from left to right across the screen (the two numbers are x and y velocities). As you can see, there are many negative numbers, and the y velocity seems to be larger than it should be.

Does anyone know what I might be doing wrong?

03-30 20:37:29.857: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    23.123592   11.537558
03-30 20:37:29.873: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    356.74066   55.184505
03-30 20:37:29.888: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    343.06155   43.027973
03-30 20:37:29.904: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    248.62907   32.232735
03-30 20:37:29.927: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    182.43666   22.957638
03-30 20:37:29.943: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    157.40408   54.90605
03-30 20:37:29.959: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    59.81672    15.241951
03-30 20:37:29.974: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    45.65707    -8.753063
03-30 20:37:29.990: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    62.7431 -23.311165
03-30 20:37:30.005: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    82.24246    -20.412537
03-30 20:37:30.029: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    101.6548    4.1870637
03-30 20:37:30.045: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    35.63154    -25.088724
03-30 20:37:30.060: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -65.35024   8.635846
03-30 20:37:30.076: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    34.84411    12.235493
03-30 20:37:30.091: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    137.96663   -32.02561
03-30 20:37:30.107: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    104.81523   4.6049824
03-30 20:37:30.130: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -15.846537  -23.924715
03-30 20:37:30.146: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    2.1034415   19.266556
03-30 20:37:30.162: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    20.578733   29.17785
03-30 20:37:30.177: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -28.217247  -42.907413
03-30 20:37:30.193: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -0.87727404 -1.170224
03-30 20:37:30.209: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -24.889711  8.474885
03-30 20:37:30.232: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    153.30855   23.77272
03-30 20:37:30.248: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    44.412945   17.595121
03-30 20:37:30.263: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -39.40518   -28.735428
03-30 20:37:30.279: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -58.433273  -2.295834
03-30 20:37:30.295: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    51.650055   -26.379906
03-30 20:37:30.310: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    152.88931   -20.75504
03-30 20:37:30.334: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    16.233286   -44.017315
03-30 20:37:30.349: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    23.231287   18.601854
03-30 20:37:30.365: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    7.3124657   38.14189
03-30 20:37:30.380: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    84.67032    -22.859661
03-30 20:37:30.396: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    22.753403   -6.019523
03-30 20:37:30.412: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    59.714558   -35.091564
03-30 20:37:30.435: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    27.547312   24.507784
03-30 20:37:30.451: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    114.54237   29.865501
03-30 20:37:30.466: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    70.55507    3.2689145
03-30 20:37:30.482: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -2.4525054  -6.8937516
03-30 20:37:30.498: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    17.924507   -40.815117
03-30 20:37:30.521: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    43.035046   0.5026546
03-30 20:37:30.537: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    95.18336    -11.013772
03-30 20:37:30.552: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -58.86387   10.808097
03-30 20:37:30.568: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -15.751452  12.716822
03-30 20:37:30.584: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    6.3607893   -19.160402
03-30 20:37:30.599: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    93.13071    12.679931
03-30 20:37:30.623: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    71.644485   -24.96885
03-30 20:37:30.638: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -12.482128  18.495268
03-30 20:37:30.654: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -107.08017  23.484608
03-30 20:37:30.670: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -1.009377   -20.781479
03-30 20:37:30.685: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    48.203453   0.5582556
03-30 20:37:30.701: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    12.369134   -34.194973
03-30 20:37:30.724: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    20.611326   14.374227
03-30 20:37:30.740: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    120.71236   56.88748
03-30 20:37:30.755: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    149.84518   14.843528
03-30 20:37:30.771: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -129.18591  -13.255397
03-30 20:37:30.787: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -110.96849  -42.02827
03-30 20:37:30.802: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -77.30668   -12.200225
03-30 20:37:30.826: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    44.793446   16.331116
03-30 20:37:30.841: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    30.79781    -47.53295
03-30 20:37:30.857: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -53.739525  -2.9649315
03-30 20:37:30.873: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -86.65882   -16.804096
03-30 20:37:30.888: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    47.278873   52.180782
03-30 20:37:30.904: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    25.044767   32.227722
03-30 20:37:30.927: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    40.374264   -65.27872
03-30 20:37:30.927: DEBUG/SlidingListViewRow(21863): ACTION_MOVE    -12.49039   -48.878017

Code:

package com.example.SlidingListViewRow;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;

public class SlidingListViewRow extends RelativeLayout {
    VelocityTracker mVelocityTracker;
    Scroller mScroller = new Scroller(getContext());


    float mStartX, mStartY;
    public SlidingListViewRow(Context context) {
        super(context);
    }

    public SlidingListViewRow(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SlidingListViewRow(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            {
                mVelocityTracker.clear();

                mScroller.abortAnimation();

                Log.d("SlidingListViewRow", "ACTION_DOWN: " + " x:" + event.getX() + " y:" + event.getY());
                mStartX = event.getX();
                mStartY = event.getY();

                mVelocityTracker.addMovement(event);

                return true;
            }
            case MotionEvent.ACTION_MOVE:
            {
                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1000);

                float vx = mVelocityTracker.getXVelocity();
                float vy = mVelocityTracker.getYVelocity();
                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
                Log.d("SlidingListViewRow", "ACTION_MOVE\t" + vx + "\t" + vy);

                lp.leftMargin = (int)(lp.leftMargin + event.getX() - mStartX);
                lp.topMargin = (int)(lp.topMargin + event.getY() - mStartY);

                setLayoutParams(lp);
                return true;
            }
            case MotionEvent.ACTION_UP:
            {
                mVelocityTracker.computeCurrentVelocity(1000);
                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();

                Log.d("SlidingListViewRow", "ACTION_UP: " + mVelocityTracker.getXVelocity() + " " + mVelocityTracker.getYVelocity());
                mScroller.forceFinished(true);
                mScroller.startScroll(lp.leftMargin, lp.topMargin,
                        (int) mVelocityTracker.getXVelocity(),
                        (int) mVelocityTracker.getYVelocity(), 1000);

                invalidate();

                mVelocityTracker.recycle();
                mVelocityTracker = null;

                return true;
            }
            case MotionEvent.ACTION_CANCEL:
            {
                mVelocityTracker.recycle();
                mVelocityTracker = null;

            }

        }
        return super.onTouchEvent(event);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            Log.d("SlidingListViewRow", "computeScroll " + mScroller.getCurrX() + " " + mScroller.getCurrY());


            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();

            lp.leftMargin = mScroller.getCurrX();
            lp.topMargin = mScroller.getCurrY();


            setLayoutParams(lp);

            invalidate();
        }
    }
}

EDIT: I think I've come closer. What appears to be happening is that the motion events are relative to the view, and because I'm moving the view, they just jitter around where I touch the view initially. Logging event.getX() and event.getY(), I get the following when dragging my finger from top to bottom. Note that x and y are pretty much always the same. So obviously, this approach does not work. Now the question is, how do I get around it?

04-06 10:55:13.460: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:241.85272 vx: 0.008770505 vy:7.7523403
04-06 10:55:13.476: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:244.04398 vx: -0.0014130835 vy:7.125545
04-06 10:55:13.491: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:242.04156 vx: -0.0018627803 vy:-8.498776
04-06 10:55:13.515: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:243.98645 vx: -0.0011581925 vy:-10.778463
04-06 10:55:13.530: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:243.67465 vx: 0.003123357 vy:-0.96067995
04-06 10:55:13.546: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:244.90335 vx: 0.0012589534 vy:20.408503
04-06 10:55:13.562: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:245.38507 vx: 0.0031079662 vy:42.45428
04-06 10:55:13.577: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:246.9231 vx: 0.00393455 vy:20.763577
04-06 10:55:13.616: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:245.3899 vx: 0.0024473427 vy:-15.408336
04-06 10:55:13.632: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:246.62701 vx: 1.6782524E-4 vy:12.024636
04-06 10:55:13.648: DEBUG/SlidingListViewRow(29988): ACTION_MOVE: x:174.0 y:247.16913 vx: 0.0032229617 vy:5.3146386
like image 919
mindvirus Avatar asked Feb 16 '23 23:02

mindvirus


2 Answers

I'll have to see your movements with your finger to see if the number matches. Some notes: - The results in emulators are completely inaccurate and unexpected in some cases. - Note that you are not tracking pointers. If at some point there is more than one pressure point in the screen, they might affect the result of the calculation of the velocity tracker.

EDIT: You are right. The events are relative to its view in its initial state (unless you change its layoutParams) what I wouldn't recommend. For what you want to do, scroll should work perfectly, which is somehow what you are doing. What is that you want to achieve? We've recently released a library I've been working on in the last months and my first approach was similar to yours. Instead explore this option:

mScroller.startScroll(sx, sy, dx, dy, duration);

Actually the code you have seems to be enough to achieve what you want. You could just avoid changing the layout params of the view which is not the goal there. It'll help to know what is your goal. Check our library out to see if it's somehow closer: https://github.com/6wunderkinder/android-sliding-layer-lib

You can find a demo app in the appstore here: https://play.google.com/store/apps/details?id=com.slidinglayersample

Let's retake it from here.

EDIT 2: Sneaking into the code of AbsListView of Android's source I saw a way that could work for you. Line 3502:

mFlingRunnable.startOverfling(-initialVelocity);

mFlingRunnable is an object of the class FlingRunnable which is defined in the same AbsListView class and implements from Runnable (http://code.metager.de/source/xref/android/1.6/frameworks/base/core/java/android/widget/AbsListView.java - line 2237). It's a huge bunch of code. There's another example of it in the Gallery class (http://code.metager.de/source/xref/android/1.6/frameworks/base/core/java/android/widget/Gallery.java) in line 1287.

The idea is to use a Runnable as a means of something that re-runs on every frame recalculating and drawing the position of the flinged object.

This might go too complex for your goal. Another idea would be to take the velocity from the velocity tracker on MotionEven.UP or CANCEL and create an animation of the position of the object calculating the destination based on the last velocity registered by the VelocityTracked: sending the object further or nearer depending on the velocity at the time the user move her finger up.

like image 123
Jose L Ugia Avatar answered Feb 19 '23 14:02

Jose L Ugia


I struggled with same problem. You are on right track that translating your view affects velocity tracker computation. To fix the problem please call

MotionEvent.offsetLocation(diffX, diffY)

where diffX, diffY are corresponding to the offset you made on layout params - so diffX in your case would be event.getX() - mStartX. Please also add motion event to tracker as last line of handling ACTION_MOVE, after you applied the offset. So your ACTION_MOVE handling should be:

case MotionEvent.ACTION_MOVE:
                    {

                        float vx = mVelocityTracker.getXVelocity();
                        float vy = mVelocityTracker.getYVelocity();
                        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
                        Log.d("SlidingListViewRow", "ACTION_MOVE\t" + vx + "\t" + vy);

                        lp.leftMargin = (int)(lp.leftMargin + event.getX() - mStartX);
                        lp.topMargin = (int)(lp.topMargin + event.getY() - mStartY);

                        setLayoutParams(lp);
                        event.offsetLocation(event.getX() - mStartX, event.getY() - mStartY);
                        mVelocityTracker.addMovement(event);
                        mVelocityTracker.computeCurrentVelocity(1000);
                        return true;
                    }
like image 26
qbasso Avatar answered Feb 19 '23 13:02

qbasso