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

后端 未结 3 1393
情话喂你
情话喂你 2021-02-01 18:32

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.

相关标签:
3条回答
  • 2021-02-01 19:00

    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 x less 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.

    0 讨论(0)
  • 2021-02-01 19:09

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

    Min and max velocity parameters are set by the manufacturer. Different device models will often use the same density bucket for resource selection purposes, but don't normally share the same physical density. 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 physical speed. The reported pixels/second would be higher on the small screen despite the fact that both phones have identical resolutions and reported densities.

    What to do with min and max velocity? Lets say the maker of the smaller screen determines 75 pixels/second is the perfect minimum 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 physical behavior (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.

    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:

    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 actual velocities 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.

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

    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.

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

    0 讨论(0)
  • 2021-02-01 19:10

    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.

    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, velocityPercentX gives you the "power" of the fling as a percent, and normalizedVelocityX is the velocity in terms of your application logic (such as an image width in device-independent pixels).

    0 讨论(0)
提交回复
热议问题