mirror of
https://github.com/status-im/react-native.git
synced 2025-01-27 01:40:08 +00:00
Add AnimatedDiffClamp node
Summary: This adds a new type of node that clamps an animated value between 2 values with a special twist, it is based on the difference between the previous value so getting far from a bound doesn't matter and as soon as we start getting closer again the value will start changing. The main use case for this node is to create a collapsible navbar when scrolling a scrollview. This is a pretty in apps (fb, youtube, twitter, all use something like this). It updates using the following: `value = clamp(value + diff, min, max)` where `diff` is the difference with the previous value. This gives the following output for parameters min = 0, max = 30: ``` in out 0 0 15 15 30 30 100 30 90 20 30 0 50 20 ``` One issue I see is that this node is pretty specific to this use case but I can't see another simple way to do this with Animated that can also be offloaded to native easily. I'd be glad to discuss other solutions if some Closes https://github.com/facebook/react-native/pull/9419 Differential Revision: D3753920 fbshipit-source-id: 40a749d38fd003aab2d3cb5cb8f0535e467d8a2a
This commit is contained in:
parent
777a9c0a0e
commit
cd1d652af4
@ -1193,6 +1193,43 @@ class AnimatedModulo extends AnimatedWithChildren {
|
||||
}
|
||||
}
|
||||
|
||||
class AnimatedDiffClamp extends AnimatedWithChildren {
|
||||
_a: Animated;
|
||||
_min: number;
|
||||
_max: number;
|
||||
_value: number;
|
||||
_lastValue: number;
|
||||
|
||||
constructor(a: Animated, min: number, max: number) {
|
||||
super();
|
||||
|
||||
this._a = a;
|
||||
this._min = min;
|
||||
this._max = max;
|
||||
this._value = this._lastValue = this._a.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
const value = this._a.__getValue();
|
||||
const diff = value - this._lastValue;
|
||||
this._lastValue = value;
|
||||
this._value = Math.min(Math.max(this._value + diff, this._min), this._max);
|
||||
return this._value;
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
this._a.__addChild(this);
|
||||
}
|
||||
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
class AnimatedTransform extends AnimatedWithChildren {
|
||||
_transforms: Array<Object>;
|
||||
|
||||
@ -1693,6 +1730,14 @@ var modulo = function(
|
||||
return new AnimatedModulo(a, modulus);
|
||||
};
|
||||
|
||||
var diffClamp = function(
|
||||
a: Animated,
|
||||
min: number,
|
||||
max: number,
|
||||
): AnimatedDiffClamp {
|
||||
return new AnimatedDiffClamp(a, min, max);
|
||||
};
|
||||
|
||||
const _combineCallbacks = function(callback: ?EndCallback, config : AnimationConfig) {
|
||||
if (callback && config.onComplete) {
|
||||
return (...args) => {
|
||||
@ -2084,6 +2129,17 @@ module.exports = {
|
||||
*/
|
||||
modulo,
|
||||
|
||||
/**
|
||||
* Create a new Animated value that is limited between 2 values. It uses the
|
||||
* difference between the last value so even if the value is far from the bounds
|
||||
* it will start changing when the value starts getting closer again.
|
||||
* (`value = clamp(value + diff, min, max)`).
|
||||
*
|
||||
* This is useful with scroll events, for example, to show the navbar when
|
||||
* scrolling up and to hide it when scrolling down.
|
||||
*/
|
||||
diffClamp,
|
||||
|
||||
/**
|
||||
* Starts an animation after the given delay.
|
||||
*/
|
||||
|
@ -567,3 +567,16 @@ describe('Animated Listeners', () => {
|
||||
expect(listener.mock.calls.length).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Animated Diff Clamp', () => {
|
||||
it('should get the proper value', () => {
|
||||
const inputValues = [0, 20, 40, 30, 0, -40, -10, -20, 0];
|
||||
const expectedValues = [0, 20, 20, 10, 0, 0, 20, 10, 20];
|
||||
const value = new Animated.Value(0);
|
||||
const diffClampValue = Animated.diffClamp(value, 0, 20);
|
||||
for (let i = 0; i < inputValues.length; i++) {
|
||||
value.setValue(inputValues[i]);
|
||||
expect(diffClampValue.__getValue()).toBe(expectedValues[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user