chore: bring flutter client, docs, deploy and tools into monorepo
This commit is contained in:
@@ -0,0 +1,566 @@
|
||||
# Curves Reference
|
||||
|
||||
Curves define the easing function for animations, controlling how values interpolate from start to end.
|
||||
|
||||
## Core Concept
|
||||
|
||||
A curve takes an input `t` (0.0 to 1.0, representing time) and outputs a value (typically 0.0 to 1.0, representing progress).
|
||||
|
||||
## Built-in Curves
|
||||
|
||||
### Linear
|
||||
|
||||
```dart
|
||||
Curves.linear
|
||||
```
|
||||
|
||||
No easing - straight line from 0 to 1. Use when you want constant speed.
|
||||
|
||||
### Ease (Sigmoid)
|
||||
|
||||
```dart
|
||||
Curves.ease
|
||||
Curves.easeIn
|
||||
Curves.easeOut
|
||||
Curves.easeInOut
|
||||
```
|
||||
|
||||
**Curves.ease** - Slow start and end, fast middle (most common)
|
||||
|
||||
**Curves.easeIn** - Slow start, fast end (accelerating)
|
||||
|
||||
**Curves.easeOut** - Fast start, slow end (decelerating)
|
||||
|
||||
**Curves.easeInOut** - Slow start and end, fast middle (combination)
|
||||
|
||||
### Cubic (Stronger Ease)
|
||||
|
||||
```dart
|
||||
Curves.easeInCubic
|
||||
Curves.easeOutCubic
|
||||
Curves.easeInOutCubic
|
||||
```
|
||||
|
||||
Stronger easing than basic ease. More dramatic slow/fast zones.
|
||||
|
||||
### Elastic (Bouncy)
|
||||
|
||||
```dart
|
||||
Curves.elasticIn
|
||||
Curves.elasticOut
|
||||
Curves.elasticInOut
|
||||
```
|
||||
|
||||
**Curves.elasticIn** - Bounces in (starts behind, shoots forward)
|
||||
|
||||
**Curves.elasticOut** - Bounces out (goes past, comes back)
|
||||
|
||||
**Curves.elasticInOut** - Bounces in and out
|
||||
|
||||
Example: Good for playful UI, notifications
|
||||
|
||||
### Bounce
|
||||
|
||||
```dart
|
||||
Curves.bounceIn
|
||||
Curves.bounceOut
|
||||
Curves.bounceInOut
|
||||
```
|
||||
|
||||
**Curves.bounceIn** - Bounces in (less bouncy than elastic)
|
||||
|
||||
**Curves.bounceOut** - Bounces out (less bouncy than elastic)
|
||||
|
||||
**Curves.bounceInOut** - Bounces in and out
|
||||
|
||||
Example: Good for feedback animations
|
||||
|
||||
### Back (Overshoot)
|
||||
|
||||
```dart
|
||||
Curves.backIn
|
||||
Curves.backOut
|
||||
Curves.backInOut
|
||||
```
|
||||
|
||||
**Curves.backIn** - Backs up before going in
|
||||
|
||||
**Curves.backOut** - Backs up before coming out
|
||||
|
||||
**Curves.backInOut** - Backs up on both ends
|
||||
|
||||
Example: Good for revealing content
|
||||
|
||||
### Decelerate (Fast then Slow)
|
||||
|
||||
```dart
|
||||
Curves.decelerate
|
||||
```
|
||||
|
||||
Fast start, very slow end. Similar to easeOut but more dramatic.
|
||||
|
||||
### Fast Out Slow In
|
||||
|
||||
```dart
|
||||
Curves.fastOutSlowIn
|
||||
```
|
||||
|
||||
Very fast start, very slow middle, very fast end. Dramatic.
|
||||
|
||||
### Custom Curves in Flutter API
|
||||
|
||||
Flutter includes specialized curves:
|
||||
|
||||
```dart
|
||||
// Material design curves
|
||||
Curves.fastLinearToSlowEaseIn
|
||||
Curves.slowMiddle
|
||||
|
||||
// Specific curves for certain transitions
|
||||
Curves.ease
|
||||
```
|
||||
|
||||
## Using Curves
|
||||
|
||||
### With Implicit Animation
|
||||
|
||||
```dart
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
width: _expanded ? 200 : 100,
|
||||
child: const FlutterLogo(),
|
||||
)
|
||||
```
|
||||
|
||||
### With Explicit Animation (CurvedAnimation)
|
||||
|
||||
```dart
|
||||
animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
```
|
||||
|
||||
### With Interval
|
||||
|
||||
```dart
|
||||
animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(
|
||||
0.0,
|
||||
0.5,
|
||||
curve: Curves.easeIn,
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
### With Curves.elasticOut
|
||||
|
||||
```dart
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
curve: Curves.elasticOut,
|
||||
transform: Matrix4.rotationZ(_rotated ? 0.5 : 0),
|
||||
child: const FlutterLogo(),
|
||||
)
|
||||
```
|
||||
|
||||
## Custom Curves
|
||||
|
||||
### Creating a Custom Curve
|
||||
|
||||
```dart
|
||||
import 'dart:math' as math;
|
||||
|
||||
class CustomCurve extends Curve {
|
||||
@override
|
||||
double transform(double t) {
|
||||
// t is 0.0 to 1.0
|
||||
// Return 0.0 to 1.0
|
||||
return math.pow(t, 2); // Quadratic ease in
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```dart
|
||||
AnimatedContainer(
|
||||
curve: CustomCurve(),
|
||||
duration: const Duration(milliseconds: 300),
|
||||
width: _expanded ? 200 : 100,
|
||||
child: const FlutterLogo(),
|
||||
)
|
||||
```
|
||||
|
||||
### Shake Curve
|
||||
|
||||
```dart
|
||||
class ShakeCurve extends Curve {
|
||||
@override
|
||||
double transform(double t) {
|
||||
return sin(t * pi * 2);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Smooth Step Curve
|
||||
|
||||
```dart
|
||||
class SmoothStep extends Curve {
|
||||
final double steps;
|
||||
|
||||
const SmoothStep({this.steps = 5});
|
||||
|
||||
@override
|
||||
double transform(double t) {
|
||||
return (t * steps).floor() / steps;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exponential Curve
|
||||
|
||||
```dart
|
||||
class ExponentialCurve extends Curve {
|
||||
final double exponent;
|
||||
|
||||
const ExponentialCurve({this.exponent = 2});
|
||||
|
||||
@override
|
||||
double transform(double t) {
|
||||
return math.pow(t, exponent);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Curve Composition
|
||||
|
||||
### Cubic Bezier
|
||||
|
||||
Flutter doesn't have built-in cubic bezier, but you can approximate:
|
||||
|
||||
```dart
|
||||
class CubicBezier extends Curve {
|
||||
final double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y;
|
||||
|
||||
const CubicBezier({
|
||||
required this.p0x,
|
||||
required this.p0y,
|
||||
required this.p1x,
|
||||
required this.p1y,
|
||||
required this.p2x,
|
||||
required this.p2y,
|
||||
required this.p3x,
|
||||
required this.p3y,
|
||||
});
|
||||
|
||||
@override
|
||||
double transform(double t) {
|
||||
// Simplified cubic bezier formula
|
||||
final u = 1 - t;
|
||||
return (u * u * u * p0y +
|
||||
3 * u * u * t * p1y +
|
||||
3 * u * t * t * p2y +
|
||||
t * t * t * p3y);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Combining Curves
|
||||
|
||||
```dart
|
||||
class CombinedCurve extends Curve {
|
||||
final Curve first;
|
||||
final Curve second;
|
||||
final double threshold;
|
||||
|
||||
const CombinedCurve({
|
||||
required this.first,
|
||||
required this.second,
|
||||
required this.threshold,
|
||||
});
|
||||
|
||||
@override
|
||||
double transform(double t) {
|
||||
if (t < threshold) {
|
||||
return first.transform(t / threshold) * threshold;
|
||||
}
|
||||
return threshold +
|
||||
second.transform((t - threshold) / (1 - threshold)) * (1 - threshold);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```dart
|
||||
AnimatedContainer(
|
||||
curve: CombinedCurve(
|
||||
first: Curves.easeIn,
|
||||
second: Curves.easeOut,
|
||||
threshold: 0.5,
|
||||
),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
width: _expanded ? 200 : 100,
|
||||
child: const FlutterLogo(),
|
||||
)
|
||||
```
|
||||
|
||||
## Choosing the Right Curve
|
||||
|
||||
### Motion Design Guidelines
|
||||
|
||||
| Animation Type | Recommended Curve | Why |
|
||||
|---------------|-------------------|-----|
|
||||
| Fade in/out | easeInOut | Natural opacity change |
|
||||
| Size change | easeOut | Decelerate feels natural for growth |
|
||||
| Position slide | easeInOut | Smooth start and stop |
|
||||
| Rotation | easeInOut | Natural angular acceleration |
|
||||
| Color change | linear | Uniform color transition |
|
||||
| Scale | elasticOut | Playful, bouncy feel |
|
||||
| Reveal | backOut | Dramatic reveal effect |
|
||||
| Loading | linear or ease | Consistent speed |
|
||||
| Success | elasticOut | Celebratory feel |
|
||||
|
||||
### Platform Conventions
|
||||
|
||||
**iOS:**
|
||||
- Prefers subtle curves (ease, easeInOut)
|
||||
- Limited use of elastic/bounce
|
||||
- Consistent with system animations
|
||||
|
||||
**Android:**
|
||||
- Wider variety of curves
|
||||
- More use of elastic/bounce for feedback
|
||||
- Material design curves (easeIn, fastOutSlowIn)
|
||||
|
||||
**Web:**
|
||||
- CSS-like curves (ease, ease-in, ease-out, ease-in-out)
|
||||
- Limited use of complex curves
|
||||
|
||||
## Curve Combinations
|
||||
|
||||
### Multi-Stage Animation
|
||||
|
||||
```dart
|
||||
// Stage 1: Ease in (0.0 - 0.5)
|
||||
// Stage 2: Ease out (0.5 - 1.0)
|
||||
|
||||
animation1 = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
|
||||
);
|
||||
|
||||
animation2 = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
|
||||
);
|
||||
```
|
||||
|
||||
### Staggered with Different Curves
|
||||
|
||||
```dart
|
||||
// Item 1: Bouncy
|
||||
item1Animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.0, 0.3, curve: Curves.elasticOut),
|
||||
);
|
||||
|
||||
// Item 2: Smooth
|
||||
item2Animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.1, 0.4, curve: Curves.easeInOut),
|
||||
);
|
||||
|
||||
// Item 3: Linear
|
||||
item3Animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: const Interval(0.2, 0.5, curve: Curves.linear),
|
||||
);
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Curve Complexity
|
||||
|
||||
Simple curves (linear, ease) are faster:
|
||||
- Fewer calculations
|
||||
- Less GPU work
|
||||
- Consistent timing
|
||||
|
||||
Complex curves (elastic, bounce) are slower:
|
||||
- More calculations
|
||||
- Potential for frame drops
|
||||
- Variable timing
|
||||
|
||||
### Optimization Tips
|
||||
|
||||
- Use simpler curves on low-end devices
|
||||
- Cache curve calculations if needed
|
||||
- Test performance on target devices
|
||||
- Profile with Flutter DevTools
|
||||
|
||||
## Debugging Curves
|
||||
|
||||
### Visualize Curve
|
||||
|
||||
```dart
|
||||
class CurveVisualizer extends StatelessWidget {
|
||||
final Curve curve;
|
||||
|
||||
const CurveVisualizer({super.key, required this.curve});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomPaint(
|
||||
painter: _CurvePainter(curve: curve),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CurvePainter extends CustomPainter {
|
||||
final Curve curve;
|
||||
|
||||
const CurvePainter({required this.curve});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = Colors.blue
|
||||
..strokeWidth = 2
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
final path = Path();
|
||||
for (double t = 0; t <= 1; t += 0.01) {
|
||||
final x = t * size.width;
|
||||
final y = size.height - (curve.transform(t) * size.height);
|
||||
if (t == 0) {
|
||||
path.moveTo(x, y);
|
||||
} else {
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_CurvePainter oldDelegate) => false;
|
||||
}
|
||||
```
|
||||
|
||||
### Print Curve Values
|
||||
|
||||
```dart
|
||||
void printCurveValues(Curve curve) {
|
||||
print('Curve: $curve');
|
||||
for (double t = 0; t <= 1; t += 0.1) {
|
||||
print('t=$t, output=${curve.transform(t)}');
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
printCurveValues(Curves.easeInOut);
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Respecting User Preferences
|
||||
|
||||
```dart
|
||||
Curve getAdaptiveCurve(BuildContext context) {
|
||||
if (MediaQuery.of(context).disableAnimations) {
|
||||
return Curves.linear; // No easing when animations disabled
|
||||
}
|
||||
return Curves.easeInOut;
|
||||
}
|
||||
```
|
||||
|
||||
### Reduced Motion
|
||||
|
||||
```dart
|
||||
AnimatedContainer(
|
||||
duration: MediaQuery.of(context).disableAnimations
|
||||
? Duration.zero
|
||||
: const Duration(milliseconds: 300),
|
||||
curve: getAdaptiveCurve(context),
|
||||
width: _expanded ? 200 : 100,
|
||||
child: const FlutterLogo(),
|
||||
)
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Loading Spinner
|
||||
|
||||
```dart
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.linear, // Constant speed
|
||||
);
|
||||
```
|
||||
|
||||
### Success Checkmark
|
||||
|
||||
```dart
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.elasticOut, // Bouncy celebration
|
||||
);
|
||||
```
|
||||
|
||||
### Page Transition
|
||||
|
||||
```dart
|
||||
_enterAnimation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeIn, // Accelerate in
|
||||
);
|
||||
|
||||
_exitAnimation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeOut, // Decelerate out
|
||||
);
|
||||
```
|
||||
|
||||
### Modal Popup
|
||||
|
||||
```dart
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeOutBack, // Dramatic reveal
|
||||
);
|
||||
```
|
||||
|
||||
## Curve Comparison
|
||||
|
||||
| Curve | Start | Middle | End | Feel |
|
||||
|-------|-------|--------|-----|------|
|
||||
| linear | Fast | Fast | Fast | Mechanical |
|
||||
| ease | Slow | Fast | Slow | Natural |
|
||||
| easeIn | Slow | Fast | Fast | Accelerating |
|
||||
| easeOut | Fast | Slow | Slow | Decelerating |
|
||||
| easeInOut | Slow | Fast | Slow | Smooth |
|
||||
| elasticIn | Back | Fast | Normal | Bouncy start |
|
||||
| elasticOut | Normal | Fast | Back | Bouncy end |
|
||||
| bounceIn | Bounce | Fast | Normal | Bouncy start |
|
||||
| bounceOut | Normal | Fast | Bounce | Bouncy end |
|
||||
| backIn | Back | Fast | Normal | Overshoot start |
|
||||
| backOut | Normal | Fast | Back | Overshoot end |
|
||||
|
||||
## Best Practices
|
||||
|
||||
### DO
|
||||
|
||||
- Use appropriate curves for animation type
|
||||
- Test on real devices
|
||||
- Consider platform conventions
|
||||
- Respect accessibility settings
|
||||
- Profile performance with DevTools
|
||||
|
||||
### DON'T
|
||||
|
||||
- Use elastic/bounce for everything (distracting)
|
||||
- Over-combine curves (confusing motion)
|
||||
- Ignore device performance
|
||||
- Use same curve for all animations (boring)
|
||||
- Forget to handle edge cases (t < 0 or t > 1)
|
||||
Reference in New Issue
Block a user