在具有相同密度的不同Android设备上具有不同的fling(滑动)速度

时间:2013-09-15 12:40:08

标签: java android android-animation android-view android-gesture

我正在编写自己的图像查看器,用户可以向左或向右滑动以查看下一张\上一张图像。我想根据投掷速度为图像变化设置动画。

为了检测一个投掷手势及其速度,我按照basic gesture detection进行了检查,并按照接受的答案建议:

public class SelectFilterActivity extends Activity implements OnClickListener
{

    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;
    View.OnTouchListener gestureListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /* ... */

        // Gesture detection
        gestureDetector = new GestureDetector(this, new MyGestureDetector());
        gestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return gestureDetector.onTouchEvent(event);
            }
        };

    }

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
                // right to left swipe
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                    Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                // nothing
            }
            return false;
        }

    }

问题在于,对于具有相同密度的不同Android设备,我获得了不同的速度值(velocityX& velocityY)。基本上,这意味着在一个设备中,滑动感觉缓慢且不敏感,而其他设备感觉太敏感。

我认为它可能与设备上的“默认”最大速度有关,可以使用 -

获取
ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()

具有相同密度的不同设备上的结果与预期不同:

    Samsung S I 480x800 density 1.5 Android 2.1
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 3600
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 4000

    HTC Desire 480x800 density 1.5 Android 2.3.3
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 6000
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 4000

    Samsung S III mini 480x800 density 1.5 Android 4.1
    getScaledMinimumFlingVelocity(): 75
    getScaledMaximumFlingVelocity(): 12000
    ViewConfiguration.MAXIMUM_FLING_VELOCITY = 8000

您还可以看到ViewConfiguration在Android 4.0以下的MAXIMUM_FLING_VELOCITY中有2个不同的值。

为什么具有相同密度和几乎相同的api级别的不同设备不具有相同的最大速度? 当用户进行滑动手势时,如何在不同设备上获得相同的体验? 我可以使用最大速度数据在所有Android设备上实现统一体验吗?

3 个答案:

答案 0 :(得分:15)

我有类似的问题。您可以将速度标准化为0到1之间的值,而不是直接使用ViewConfiguration的最大和最小速度。

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    float maxFlingVelocity    = ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity();
    float velocityPercentX    = velocityX / maxFlingVelocity;          // the percent is a value in the range of (0, 1]
    float normalizedVelocityX = velocityPercentX * PIXELS_PER_SECOND;  // where PIXELS_PER_SECOND is a device-independent measurement

换句话说,velocityPercentX以百分比的形式为您提供“权力”,normalizedVelocityX是应用程序逻辑方面的速度(例如与设备无关的图像宽度)像素)。

答案 1 :(得分:6)

  

为什么不同的设备具有相同的密度和几乎相同的api级别   没有相同的最大速度?

最小和最大速度参数由制造商设定。不同的设备型号通常会使用相同的密度存储桶进行资源选择,但通常不会共享相同的物理密度。假设存在具有相同分辨率和相同报告密度1.5的4“电话和5”电话。想象一下,以相同的物理速度在两个屏幕上滑动。尽管这两款手机具有相同的分辨率和报告的密度,但在小屏幕上报告的像素/秒将更高

如何处理最小和最大速度?让我们说,较小屏幕的制造商确定75像素/秒是完美最小手指速度,然后报告一个投掷手势。任何较小的都会导致因触摸错误而意外晃动,任何较大的都会需要过于谨慎的手势来扔东西。如果大型手机的制造商想要匹配较小手机的相同的完美物理行为(相同的手指速度),则需要将最小速度调整为较小的数量。由于物理特性,较大设备的制造商将需要较少的像素/秒来启动投掷。屏幕灵敏度等其他因素可能是不同制造商的因素。

  

如何在用户时在不同设备上获得相同的体验   做一个轻扫手势?

使用以像素/秒为单位的速度来配置动画。简单地避免使用与密度无关的参数,您应该能够精确匹配速度。请注意,这与最小或最大速度值无关。但是,您需要根据指定的密度将SWIPE_THRESHOLD_VELOCITY计算为“原始”像素值。这就是Android的Launcher2计算主屏幕项目flings的密度无关阈值速度的方法:

int DENSITY_INDEPENDENT_THRESHOLD = 200;
Resources r = getResources();
float density = r.getDisplayMetrics().density;
SWIPE_THRESHOLD_VELOCITY = (int)(DENSITY_INDEPENDENT_THRESHOLD * density);

请注意,上述示例中的4“手机和5”手机的此阈值相同。这不会影响实际速度,因为我们这里只讨论一个阈值。您只需要在5英寸手机上刷卡比在4英寸手机上快20%即可打破门槛。 Android启动程序在y方向使用-1500的DENSITY_INDEPENDENT_THRESHOLD,但200个声音适合您的应用程序。

  

我可以使用最大速度数据来获得统一的体验   所有Android设备?

没有。最大速度是一个边缘情况,您不需要正确设置动画。我怀疑用户会以最大速度投掷任何东西,除非他们正在玩游戏,并且用户无论如何动画都能以6000像素/秒的速度完美匹配。

TL; DR使用来自onFling参数的原始速度来精确配置动画和匹配速度。避免使用与密度无关的参数来配置fling动画。

答案 2 :(得分:0)

不要使用速度:它不容易使用。向右滑动它是一个+数字,在左边它是一个数字。你可以这些:

event1.getRawY() 
event2.getRawY()
event1.getRawX() 
event2.getRawX()

确定滑动是左还是右:

如果第一个事件超过第二个事件,那个人向左滑动,但你可以说最后一个事件是否比第一个事件少x,那么这个人的刷卡就足够了并做出反应它。您可以执行相反的操作,向右滑动。此外,onFling无法识别小型水龙头和触摸,因此您可以在不比较距离速度或长度的情况下离开。