Application scenarios

Swiper 4.x takes over the scrolling of a page using swiper4. Used to support the top and tail bounces, further supporting the common pull-down refresh animation. It is not applicable to the application scenario of the round broadcast graph.

This is just for Swiper 4.x, but the principle is also useful in other frameworks.

Problems arising

Inertial animation does not stop at touch

Quick slide page, hand off the screen generated inertia animation is still running, touch the screen at this time, animation will not stop. The result is a rapid succession of pages that appear to jump around.

Fast sliding gesture is most likely to be identified as slow sliding gesture

After a few consecutive quick slides, one or two slides can obviously perceive the slow animation of sliding inertia, which gives people the feeling that sliding is not smooth.

Third, the length of inertia animation is unreasonable

The inertia animation duration can only be set to a fixed value for a slow slide or a fast slide. After moving slowly and letting go, there will be a very long animation. When skating at fast speed, the animation is a little short, which makes people feel very stuck.

solution

In addition to the first problem, two other problems seem insurmountable without modifying the swiper4.x source code.

First, solve the problem that inertial animation will not stop at touch

The inertial animation generated when the hand leaves the screen while sliding is a CSS animation and does not directly provide a way to stop the animation. If we touch the screen while the animation is still running and we don’t change the source code, we’re going to listen for the touchStart event.

To remove this animated CSS, use setTranslate, which provides the current scrolling position of the page. Just use getTranslate() :

This is slightly different from the value obtained by the myswiper.Translate attribute, even in animating, which is more precise

Solution code

// Execute in the touchStart event
mySwiper.setTranslate(mySwiper.getTranslate());
Copy the code

Second, to solve the problem of fast sliding gesture recognition into slow sliding gesture

This must modify the source code to solve the problem in the calculation of inertia animation starting speed of the calculation parameters precision is not enough.

The original code

if (params.freeModeMomentum) {
        if(data.velocities.length > 1) { var lastMoveEvent = data.velocities.pop(); var velocityEvent = data.velocities.pop(); Var distance = lastMoveEvent.position-velocityevent.position; var time = lastMoveEvent.time - velocityEvent.time; swiper.velocity = distance / time; swiper.velocity /= 2;Copy the code

It can be seen that his calculation of initial velocity refers to the last two points recorded by onTouchMove. It is not reliable to simply take the last two points, and the calculated velocity may be too low due to the long triggering interval between the last two onTouchMove. And that leads to an occasional fast slide but the inertia effect is a slow slide effect.

If the trigger interval is so short that the animation gets faster, it doesn’t really make a difference in perception. The worst part is being slow. It feels so slow.

The solution

It is unlikely that a person’s sliding direction will change in a short period of time, but the sliding displacement generated in this short period of time can be a good proxy for the sliding speed at the end of the gesture.

After repeated attempts, it is best to use displacement within 100 milliseconds to calculate the initial inertia speed. Within 100 milliseconds, if it is a fast slide, multiple onTouchMove will be triggered, and the calculated speed is very close to the actual gesture speed.

The solution to the problem points to the first point in 100 milliseconds. Solution code:

if (params.freeModeMomentum) {
        if (data.velocities.length > 1) {
			// Fix inertial animation
			var velos=data.velocities;
			var firstEvent=velos[0];
			var lastMoveEvent = velos.pop();
			var velocityEvent =velos.pop();
			for(var i=velos.length- 1; i>=0; i--){// Find the starting position within 100 milliseconds
				var velo=velos[i];
				if(lastMoveEvent.time-velo.time>100) {break;
				}
				velocityEvent=velo;
			}

          var distance = lastMoveEvent.position - velocityEvent.position;
          var time = lastMoveEvent.time - velocityEvent.time;
          swiper.velocity = distance / time;
          swiper.velocity /= 2;
Copy the code

Third, to solve the problem of unreasonable duration of inertia animation

Slow sliding should have very little inertia and very short animation; You should have a lot of inertia and a long animation when you slide fast. Swiper4.x can only provide a fixed inertia animation duration, which cannot be fixed without changing the source code.

The original code is a little bit below the second question code

var momentumDuration = 1000 * params.freeModeMomentumRatio; // Write a fixed animation length
Copy the code

Optimization of the animation

In fact, simple, small is small, large is large, using the initial velocity to do the multiplication operation can achieve the effect.

var momentumDuration = Math.abs(swiper.velocity) * 1000 * params.freeModeMomentumRatio;
Copy the code

The result: much better than the original code, but different from other apps in the sliding is still a bit too fast.

App native sliding animation, perception is slow slower, fast faster. Slide a little slow as hell, move a little fast, really fast.

Logarithmic curve! The 1-0 range is fine, the slow ones are slower than the linear ones, and the steep ones are extremely steep. Using logarithmic addition to the above optimization results, the result is very good. In addition, the maximum animation limit is 3 seconds.

// Take the logarithmic curve to optimize between 0.5-1.5 times, the slower the slower, the faster the faster
momentumDuration*=-Math.log10(Math.min(0.3.Math.max(0.03, (3000-momentumDuration)/3000)));
Copy the code

Solution code

// Determine the duration of the inertial animation based on the initial speed
var momentumDuration = Math.min(3000.Math.abs(swiper.velocity) * 1000 * params.freeModeMomentumRatio);
// Take the logarithmic curve to optimize between 0.5-1.5 times, the slower the slower, the faster the faster
momentumDuration*=-Math.log10(Math.min(0.3.Math.max(0.03, (3000-momentumDuration)/3000)));
momentumDuration=Math.min(3000,momentumDuration);
Copy the code

The final result

Swiper4.x modified single-page scrolling effect is very close to the scrolling effect of App. Although there is still a slight sense of jitter and stutter, it is difficult to achieve completely the same smooth effect as App. Currently, it is quite good.

Iscroll is easier, but I’ve already boarded the Swiper 4.x ship.

[2019-02-27] jiebian.life/start/ XCX /t Experience (the new version will not be available before this time), applet and H5 shared page.