Java 相同密度的不同 Android 设备上的不同甩动(滑动)速度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18812479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:16:28  来源:igfitidea点击:

Different fling (swipe) velocity on different Android devices with same density

javaandroidandroid-animationandroid-viewandroid-gesture

提问by Ron Tesler

I'm writing my own image viewer that enables users to swipe left\right to see the next\previous image. I want to animate the image change according to the fling velocity.

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

To detect a fling gesture and its velocity, I followed this basic gesture detectionand did as the accepted answer suggested:

为了检测甩动手势及其速度,我遵循了这个基本的手势检测,并按照公认的答案进行了操作:

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;
        }

    }

The problem is that I get different velocity values (velocityX & velocityY) for different Android devices with samedensity. Basically it means that in one device the swipe feels slow and not-sensitive, and other devices feels too sensitive.

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

I thought it might have something to do with the "default" maximum velocity on the device, that can be fetched using -

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

ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()

The results on different devices with same density aren't the same as expected:

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

    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

You can also see that ViewConfigurationhas 2 different values for MAXIMUM_FLING_VELOCITYin Android below 4.0 and above.

您还可以看到ViewConfigurationMAXIMUM_FLING_VELOCITY在 Android 4.0 及以上版本中具有 2 个不同的值。

How come different devices with same density and almost same api level don't have the same max velocity? How can I get the same experience on different devices when a user makes a swipe gesture? Can I use the max velocity data to make a uniform experience across all Android devices?

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

回答by superuser

Don't use the velocity: it is not easy to use. A swipe to the right it is a + number, to the left it is a - number. You could these:

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

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

to determine if the swipe was left or right:

确定滑动是向左还是向右:

if the first event was more than the second, the person swiped to the left, but you can say if the last event was xless than the first event, then the person's swipe was far enough and react to it. You can do the opposite for a swipe was to a right. Also, the onFling doesn't recognize small taps and just touches, so you can get away without comparing the distance velocity or length at all.

如果第一个事件比第二个事件多,则该人向左滑动,但您可以说如果最后一个事件x小于第一个事件,则该人的滑动距离足够远并对其做出反应。你可以做相反的滑动是向右。此外,onFling 无法识别轻敲和触摸,因此您无需比较距离速度或长度就可以逃脱。

回答by Bryan W. Wagner

I had a similar problem. Instead of working directly with the max and min fling velocities from ViewConfiguration, you can normalize the velocity to a value between 0 and 1.

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

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

In other words, velocityPercentXgives you the "power" of the fling as a percent, and normalizedVelocityXis the velocity in terms of your application logic (such as an image width in device-independent pixels).

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

回答by Rich Ehmer

How come different devices with same density and almost same api level don't have the same max velocity?

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

Min and max velocity parameters are set by the manufacturer. Different device models will often use the same density bucketfor resource selection purposes, but don't normally share the same physicaldensity. Assume the existence of a 4" phone and a 5" phone with identical resolutions and an identical reported density of 1.5. Imagine swiping over both screens at the same physicalspeed. The reported pixels/second would be higheron the small screen despite the fact that both phones have identical resolutions and reported densities.

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

What to do with min and max velocity? Lets say the maker of the smaller screen determines 75 pixels/second is the perfectminimum finger velocity before reporting a fling gesture. Any smaller would result in accidental flings from touch error, any larger would require too deliberate of a gesture to fling something. If the manufacturer of the large phone wanted to match the same perfect physicalbehavior (same finger speed) of the smaller phone, they would need to adjust the minimum velocity to be a smaller number. The maker of the larger device would require less pixels/second to initiate a fling due to physical characteristics. Other factors like screen sensitivity probably factor in for different manufacturers.

如何处理最小和最大速度?假设较小屏幕的制造商确定 75 像素/秒是报告滑动手势之前完美的最小手指速度。任何较小的都会导致触摸错误的意外甩动,任何较大的都会需要过于刻意的手势来甩动某物。如果大手机的制造商想要匹配小手机的完美物理行为(相同的手指速度),他们需要将最小速度调整为较小的数字。由于物理特性,较大设备的制造商将需要更少的像素/秒来启动投掷。屏幕灵敏度等其他因素可能会影响不同的制造商。

How can I get the same experience on different devices when a user makes a swipe gesture?

当用户做出滑动手势时,如何在不同的设备上获得相同的体验?

Use the velocity given in pixels/second to configure the animations. Simply avoid the use of density independent parameters and you should be able to match the velocity exactly. Notice that this has nothing to do with the min or max velocity values. However, you would want to calculate your SWIPE_THRESHOLD_VELOCITY to be a 'raw' pixel value based on the stated density. This is how Android's Launcher2 calculates density independent threshold velocity for home screen item flings:

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

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

Notice this threshold would be the same for both the 4" phone and the 5" phone in the example above. This does not affect actualvelocities because we're only talking about a threshold here. You would simply need to swipe 20% faster on the 5" phone than on the 4" phone to break the threshold. The Android launcher uses a DENSITY_INDEPENDENT_THRESHOLD of -1500 in the y direction, but 200 sounds about right for your application.

请注意,上例中的 4" 电话和 5" 电话的此阈值相同。这不会影响实际速度,因为我们在这里只讨论阈值。您只需在 5" 手机上比在 4" 手机上刷卡速度快 20% 即可突破门槛。Android 启动器在 y 方向使用 -1500 的 DENSITY_INDEPENDENT_THRESHOLD,但 200 听起来适合您的应用程序。

Can I use the max velocity data to make a uniform experience across all Android devices?

我可以使用最大速度数据在所有 Android 设备上提供统一的体验吗?

No. Max velocity is an edge case you don't need to animate correctly. I doubt users will fling anything at the max velocity unless they're playing a game, and users won't care if the animation matches perfectly at a velocity of 6000 pixels/second anyway.

不。最大速度是一种边缘情况,您不需要正确设置动画。我怀疑用户会以最大速度投掷任何东西,除非他们正在玩游戏,而且用户不会关心动画是否以 6000 像素/秒的速度完美匹配。

TL;DR Use raw velocities from onFling arguments to configure animations and match speeds exactly. Avoid using density independent parameters to configure fling animations.

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