mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
switched to a double variant of clamp to avoid boxing (#103559)
This commit is contained in:
parent
32157e3fcb
commit
64a0c19652
73
dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart
Normal file
73
dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
|
||||
import '../common.dart';
|
||||
|
||||
const int _kBatchSize = 100000;
|
||||
const int _kNumIterations = 1000;
|
||||
|
||||
void main() {
|
||||
assert(false,
|
||||
"Don't run benchmarks in debug mode! Use 'flutter run --release'.");
|
||||
final BenchmarkResultPrinter printer = BenchmarkResultPrinter();
|
||||
|
||||
final Stopwatch watch = Stopwatch();
|
||||
{
|
||||
final List<double> clampDoubleValues = <double>[];
|
||||
for (int j = 0; j < _kNumIterations; ++j) {
|
||||
double tally = 0;
|
||||
watch.reset();
|
||||
watch.start();
|
||||
for (int i = 0; i < _kBatchSize; i += 1) {
|
||||
tally += clampDouble(-1.0, 0.0, 1.0);
|
||||
tally += clampDouble(2.0, 0.0, 1.0);
|
||||
tally += clampDouble(0.0, 0.0, 1.0);
|
||||
tally += clampDouble(double.nan, 0.0, 1.0);
|
||||
}
|
||||
watch.stop();
|
||||
clampDoubleValues.add(watch.elapsedMicroseconds.toDouble() / _kBatchSize);
|
||||
if (tally < 0.0) {
|
||||
print("This shouldn't happen.");
|
||||
}
|
||||
}
|
||||
|
||||
printer.addResultStatistics(
|
||||
description: 'clamp - clampDouble',
|
||||
values: clampDoubleValues,
|
||||
unit: 'us per iteration',
|
||||
name: 'clamp_clampDouble',
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
final List<double> doubleClampValues = <double>[];
|
||||
|
||||
for (int j = 0; j < _kNumIterations; ++j) {
|
||||
double tally = 0;
|
||||
watch.reset();
|
||||
watch.start();
|
||||
for (int i = 0; i < _kBatchSize; i += 1) {
|
||||
tally += -1.0.clamp(0.0, 1.0);
|
||||
tally += 2.0.clamp(0.0, 1.0);
|
||||
tally += 0.0.clamp(0.0, 1.0);
|
||||
tally += double.nan.clamp(0.0, 1.0);
|
||||
}
|
||||
watch.stop();
|
||||
doubleClampValues.add(watch.elapsedMicroseconds.toDouble() / _kBatchSize);
|
||||
if (tally < 0.0) {
|
||||
print("This shouldn't happen.");
|
||||
}
|
||||
}
|
||||
|
||||
printer.addResultStatistics(
|
||||
description: 'clamp - Double.clamp',
|
||||
values: doubleClampValues,
|
||||
unit: 'us per iteration',
|
||||
name: 'clamp_Double_clamp',
|
||||
);
|
||||
}
|
||||
printer.printToStdout();
|
||||
}
|
||||
@ -88,6 +88,9 @@ Future<void> run(List<String> arguments) async {
|
||||
exitWithError(<String>['The analyze.dart script must be run with --enable-asserts.']);
|
||||
}
|
||||
|
||||
print('$clock No Double.clamp');
|
||||
await verifyNoDoubleClamp(flutterRoot);
|
||||
|
||||
print('$clock All tool test files end in _test.dart...');
|
||||
await verifyToolTestsEndInTestDart(flutterRoot);
|
||||
|
||||
@ -203,6 +206,80 @@ Future<void> run(List<String> arguments) async {
|
||||
|
||||
// TESTS
|
||||
|
||||
FeatureSet _parsingFeatureSet() => FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: Version.parse('2.17.0-0'),
|
||||
flags: <String>['super-parameters']);
|
||||
|
||||
_Line _getLine(ParseStringResult parseResult, int offset) {
|
||||
final int lineNumber =
|
||||
parseResult.lineInfo.getLocation(offset).lineNumber;
|
||||
final String content = parseResult.content.substring(
|
||||
parseResult.lineInfo.getOffsetOfLine(lineNumber - 1),
|
||||
parseResult.lineInfo.getOffsetOfLine(lineNumber) - 1);
|
||||
return _Line(lineNumber, content);
|
||||
}
|
||||
|
||||
class _DoubleClampVisitor extends RecursiveAstVisitor<CompilationUnit> {
|
||||
_DoubleClampVisitor(this.parseResult);
|
||||
|
||||
final List<_Line> clamps = <_Line>[];
|
||||
final ParseStringResult parseResult;
|
||||
|
||||
@override
|
||||
CompilationUnit? visitMethodInvocation(MethodInvocation node) {
|
||||
if (node.methodName.name == 'clamp') {
|
||||
final _Line line = _getLine(parseResult, node.function.offset);
|
||||
if (!line.content.contains('// ignore_clamp_double_lint')) {
|
||||
clamps.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
node.visitChildren(this);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that we use clampDouble instead of Double.clamp for performance reasons.
|
||||
///
|
||||
/// We currently can't distinguish valid uses of clamp from problematic ones so
|
||||
/// if the clamp is operating on a type other than a `double` the
|
||||
/// `// ignore_clamp_double_lint` comment must be added to the line where clamp is
|
||||
/// invoked.
|
||||
///
|
||||
/// See also:
|
||||
/// * https://github.com/flutter/flutter/pull/103559
|
||||
/// * https://github.com/flutter/flutter/issues/103917
|
||||
Future<void> verifyNoDoubleClamp(String workingDirectory) async {
|
||||
final String flutterLibPath = '$workingDirectory/packages/flutter/lib';
|
||||
final Stream<File> testFiles =
|
||||
_allFiles(flutterLibPath, 'dart', minimumMatches: 100);
|
||||
final List<String> errors = <String>[];
|
||||
await for (final File file in testFiles) {
|
||||
try {
|
||||
final ParseStringResult parseResult = parseFile(
|
||||
featureSet: _parsingFeatureSet(),
|
||||
path: file.absolute.path,
|
||||
);
|
||||
final _DoubleClampVisitor visitor = _DoubleClampVisitor(parseResult);
|
||||
visitor.visitCompilationUnit(parseResult.unit);
|
||||
for (final _Line clamp in visitor.clamps) {
|
||||
errors.add('${file.path}:${clamp.line}: `clamp` method used without ignore_clamp_double_lint comment.');
|
||||
}
|
||||
} catch (ex) {
|
||||
// TODO(gaaclarke): There is a bug with super parameter parsing on mac so
|
||||
// we skip certain files until that is fixed.
|
||||
// https://github.com/dart-lang/sdk/issues/49032
|
||||
print('skipping ${file.path}: $ex');
|
||||
}
|
||||
}
|
||||
if (errors.isNotEmpty) {
|
||||
exitWithError(<String>[
|
||||
...errors,
|
||||
'\n${bold}See: https://github.com/flutter/flutter/pull/103559',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify tool test files end in `_test.dart`.
|
||||
///
|
||||
/// The test runner will only recognize files ending in `_test.dart` as tests to
|
||||
@ -518,16 +595,16 @@ Future<int> _verifyNoMissingLicenseForExtension(
|
||||
return 0;
|
||||
}
|
||||
|
||||
class _TestSkip {
|
||||
_TestSkip(this.line, this.content);
|
||||
class _Line {
|
||||
_Line(this.line, this.content);
|
||||
|
||||
final int line;
|
||||
final String content;
|
||||
}
|
||||
|
||||
Iterable<_TestSkip> _getTestSkips(File file) {
|
||||
Iterable<_Line> _getTestSkips(File file) {
|
||||
final ParseStringResult parseResult = parseFile(
|
||||
featureSet: FeatureSet.fromEnableFlags2(sdkLanguageVersion: Version.parse('2.17.0-0'), flags: <String>['super-parameters']),
|
||||
featureSet: _parsingFeatureSet(),
|
||||
path: file.absolute.path,
|
||||
);
|
||||
final _TestSkipLinesVisitor<CompilationUnit> visitor = _TestSkipLinesVisitor<CompilationUnit>(parseResult);
|
||||
@ -536,10 +613,10 @@ Iterable<_TestSkip> _getTestSkips(File file) {
|
||||
}
|
||||
|
||||
class _TestSkipLinesVisitor<T> extends RecursiveAstVisitor<T> {
|
||||
_TestSkipLinesVisitor(this.parseResult) : skips = <_TestSkip>{};
|
||||
_TestSkipLinesVisitor(this.parseResult) : skips = <_Line>{};
|
||||
|
||||
final ParseStringResult parseResult;
|
||||
final Set<_TestSkip> skips;
|
||||
final Set<_Line> skips;
|
||||
|
||||
static bool isTestMethod(String name) {
|
||||
return name.startsWith('test') || name == 'group' || name == 'expect';
|
||||
@ -550,10 +627,7 @@ class _TestSkipLinesVisitor<T> extends RecursiveAstVisitor<T> {
|
||||
if (isTestMethod(node.methodName.toString())) {
|
||||
for (final Expression argument in node.argumentList.arguments) {
|
||||
if (argument is NamedExpression && argument.name.label.name == 'skip') {
|
||||
final int lineNumber = parseResult.lineInfo.getLocation(argument.beginToken.charOffset).lineNumber;
|
||||
final String content = parseResult.content.substring(parseResult.lineInfo.getOffsetOfLine(lineNumber - 1),
|
||||
parseResult.lineInfo.getOffsetOfLine(lineNumber) - 1);
|
||||
skips.add(_TestSkip(lineNumber, content));
|
||||
skips.add(_getLine(parseResult, argument.beginToken.charOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -571,7 +645,7 @@ Future<void> verifySkipTestComments(String workingDirectory) async {
|
||||
.where((File f) => f.path.endsWith('_test.dart'));
|
||||
|
||||
await for (final File file in testFiles) {
|
||||
for (final _TestSkip skip in _getTestSkips(file)) {
|
||||
for (final _Line skip in _getTestSkips(file)) {
|
||||
final Match? match = _skipTestCommentPattern.firstMatch(skip.content);
|
||||
final String? skipComment = match?.group(1);
|
||||
if (skipComment == null ||
|
||||
|
||||
@ -60,6 +60,7 @@ TaskFunction createMicrobenchmarkTask() {
|
||||
...await runMicrobench('lib/language/sync_star_bench.dart'),
|
||||
...await runMicrobench('lib/language/sync_star_semantics_bench.dart'),
|
||||
...await runMicrobench('lib/foundation/all_elements_bench.dart'),
|
||||
...await runMicrobench('lib/foundation/clamp.dart'),
|
||||
...await runMicrobench('lib/foundation/change_notifier_bench.dart'),
|
||||
...await runMicrobench('lib/foundation/standard_method_codec_bench.dart'),
|
||||
...await runMicrobench('lib/foundation/standard_message_codec_bench.dart'),
|
||||
|
||||
@ -33,6 +33,7 @@ export 'src/foundation/diagnostics.dart';
|
||||
export 'src/foundation/isolates.dart';
|
||||
export 'src/foundation/key.dart';
|
||||
export 'src/foundation/licenses.dart';
|
||||
export 'src/foundation/math.dart';
|
||||
export 'src/foundation/node.dart';
|
||||
export 'src/foundation/object.dart';
|
||||
export 'src/foundation/observer_list.dart';
|
||||
|
||||
@ -395,7 +395,7 @@ class AnimationController extends Animation<double>
|
||||
}
|
||||
|
||||
void _internalSetValue(double newValue) {
|
||||
_value = newValue.clamp(lowerBound, upperBound);
|
||||
_value = clampDouble(newValue, lowerBound, upperBound);
|
||||
if (_value == lowerBound) {
|
||||
_status = AnimationStatus.dismissed;
|
||||
} else if (_value == upperBound) {
|
||||
@ -598,7 +598,7 @@ class AnimationController extends Animation<double>
|
||||
stop();
|
||||
if (simulationDuration == Duration.zero) {
|
||||
if (value != target) {
|
||||
_value = target.clamp(lowerBound, upperBound);
|
||||
_value = clampDouble(target, lowerBound, upperBound);
|
||||
notifyListeners();
|
||||
}
|
||||
_status = (_direction == _AnimationDirection.forward) ?
|
||||
@ -741,7 +741,7 @@ class AnimationController extends Animation<double>
|
||||
assert(!isAnimating);
|
||||
_simulation = simulation;
|
||||
_lastElapsedDuration = Duration.zero;
|
||||
_value = simulation.x(0.0).clamp(lowerBound, upperBound);
|
||||
_value = clampDouble(simulation.x(0.0), lowerBound, upperBound);
|
||||
final TickerFuture result = _ticker!.start();
|
||||
_status = (_direction == _AnimationDirection.forward) ?
|
||||
AnimationStatus.forward :
|
||||
@ -820,7 +820,7 @@ class AnimationController extends Animation<double>
|
||||
_lastElapsedDuration = elapsed;
|
||||
final double elapsedInSeconds = elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond;
|
||||
assert(elapsedInSeconds >= 0.0);
|
||||
_value = _simulation!.x(elapsedInSeconds).clamp(lowerBound, upperBound);
|
||||
_value = clampDouble(_simulation!.x(elapsedInSeconds), lowerBound, upperBound);
|
||||
if (_simulation!.isDone(elapsedInSeconds)) {
|
||||
_status = (_direction == _AnimationDirection.forward) ?
|
||||
AnimationStatus.completed :
|
||||
@ -855,7 +855,7 @@ class _InterpolationSimulation extends Simulation {
|
||||
|
||||
@override
|
||||
double x(double timeInSeconds) {
|
||||
final double t = (timeInSeconds / _durationInSeconds).clamp(0.0, 1.0);
|
||||
final double t = clampDouble(timeInSeconds / _durationInSeconds, 0.0, 1.0);
|
||||
if (t == 0.0)
|
||||
return _begin;
|
||||
else if (t == 1.0)
|
||||
|
||||
@ -182,7 +182,7 @@ class Interval extends Curve {
|
||||
assert(end >= 0.0);
|
||||
assert(end <= 1.0);
|
||||
assert(end >= begin);
|
||||
t = ((t - begin) / (end - begin)).clamp(0.0, 1.0);
|
||||
t = clampDouble((t - begin) / (end - begin), 0.0, 1.0);
|
||||
if (t == 0.0 || t == 1.0)
|
||||
return t;
|
||||
return curve.transform(t);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart' show kMinFlingVelocity, kLongPressTimeout;
|
||||
import 'package:flutter/scheduler.dart';
|
||||
@ -958,7 +959,7 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
|
||||
_moveAnimation = Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: Offset(
|
||||
endX.clamp(-_kPadding, _kPadding),
|
||||
clampDouble(endX, -_kPadding, _kPadding),
|
||||
endY,
|
||||
),
|
||||
).animate(
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -157,7 +158,7 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin
|
||||
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final Offset midpointAnchor = Offset(
|
||||
(widget.selectionMidpoint.dx - widget.globalEditableRegion.left).clamp(
|
||||
clampDouble(widget.selectionMidpoint.dx - widget.globalEditableRegion.left,
|
||||
mediaQuery.padding.left,
|
||||
mediaQuery.size.width - mediaQuery.padding.right,
|
||||
),
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -375,7 +376,7 @@ class CupertinoSliverRefreshControl extends StatefulWidget {
|
||||
double refreshTriggerPullDistance,
|
||||
double refreshIndicatorExtent,
|
||||
) {
|
||||
final double percentageComplete = (pulledExtent / refreshTriggerPullDistance).clamp(0.0, 1.0);
|
||||
final double percentageComplete = clampDouble(pulledExtent / refreshTriggerPullDistance, 0.0, 1.0);
|
||||
|
||||
// Place the indicator at the top of the sliver that opens up. Note that we're using
|
||||
// a Stack/Positioned widget because the CupertinoActivityIndicator does some internal
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -434,7 +435,7 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
|
||||
double _currentDragValue = 0.0;
|
||||
|
||||
double get _discretizedCurrentDragValue {
|
||||
double dragValue = _currentDragValue.clamp(0.0, 1.0);
|
||||
double dragValue = clampDouble(_currentDragValue, 0.0, 1.0);
|
||||
if (divisions != null)
|
||||
dragValue = (dragValue * divisions!).round() / divisions!;
|
||||
return dragValue;
|
||||
@ -554,8 +555,8 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
|
||||
config.onIncrease = _increaseAction;
|
||||
config.onDecrease = _decreaseAction;
|
||||
config.value = '${(value * 100).round()}%';
|
||||
config.increasedValue = '${((value + _semanticActionUnit).clamp(0.0, 1.0) * 100).round()}%';
|
||||
config.decreasedValue = '${((value - _semanticActionUnit).clamp(0.0, 1.0) * 100).round()}%';
|
||||
config.increasedValue = '${(clampDouble(value + _semanticActionUnit, 0.0, 1.0) * 100).round()}%';
|
||||
config.decreasedValue = '${(clampDouble(value - _semanticActionUnit, 0.0, 1.0) * 100).round()}%';
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,11 +564,11 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
|
||||
|
||||
void _increaseAction() {
|
||||
if (isInteractive)
|
||||
onChanged!((value + _semanticActionUnit).clamp(0.0, 1.0));
|
||||
onChanged!(clampDouble(value + _semanticActionUnit, 0.0, 1.0));
|
||||
}
|
||||
|
||||
void _decreaseAction() {
|
||||
if (isInteractive)
|
||||
onChanged!((value - _semanticActionUnit).clamp(0.0, 1.0));
|
||||
onChanged!(clampDouble(value - _semanticActionUnit, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,7 +494,7 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
|
||||
final int numOfChildren = widget.children.length;
|
||||
assert(renderBox.hasSize);
|
||||
assert(numOfChildren >= 2);
|
||||
int index = (dx ~/ (renderBox.size.width / numOfChildren)).clamp(0, numOfChildren - 1);
|
||||
int index = (dx ~/ (renderBox.size.width / numOfChildren)).clamp(0, numOfChildren - 1); // ignore_clamp_double_lint
|
||||
|
||||
switch (Directionality.of(context)) {
|
||||
case TextDirection.ltr:
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@ -91,7 +92,7 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe
|
||||
// The toolbar should appear below the TextField when there is not enough
|
||||
// space above the TextField to show it, assuming there's always enough
|
||||
// space at the bottom in this case.
|
||||
final double anchorX = (widget.selectionMidpoint.dx + widget.globalEditableRegion.left).clamp(
|
||||
final double anchorX = clampDouble(widget.selectionMidpoint.dx + widget.globalEditableRegion.left,
|
||||
_kArrowScreenPadding + mediaQuery.padding.left,
|
||||
mediaQuery.size.width - mediaQuery.padding.right - _kArrowScreenPadding,
|
||||
);
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:meta/meta.dart';
|
||||
import 'assertions.dart';
|
||||
import 'constants.dart';
|
||||
import 'debug.dart';
|
||||
import 'math.dart' show clampDouble;
|
||||
import 'object.dart';
|
||||
|
||||
// Examples can assume:
|
||||
@ -2044,7 +2045,7 @@ class PercentProperty extends DoubleProperty {
|
||||
final double? v = value;
|
||||
if (v == null)
|
||||
return value.toString();
|
||||
return '${(v.clamp(0.0, 1.0) * 100.0).toStringAsFixed(1)}%';
|
||||
return '${(clampDouble(v, 0.0, 1.0) * 100.0).toStringAsFixed(1)}%';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
packages/flutter/lib/src/foundation/math.dart
Normal file
23
packages/flutter/lib/src/foundation/math.dart
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// Same as [num.clamp] but optimized for non-null [double].
|
||||
///
|
||||
/// This is faster because it avoids polymorphism, boxing, and special cases for
|
||||
/// floating point numbers.
|
||||
//
|
||||
// See also: //dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart
|
||||
double clampDouble(double x, double min, double max) {
|
||||
assert(min <= max && !max.isNaN && !min.isNaN);
|
||||
if (x < min) {
|
||||
return min;
|
||||
}
|
||||
if (x > max) {
|
||||
return max;
|
||||
}
|
||||
if (x.isNaN) {
|
||||
return max;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'arena.dart';
|
||||
import 'events.dart';
|
||||
import 'recognizer.dart';
|
||||
@ -331,7 +332,7 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
// If the device incorrectly reports a pressure outside of pressureMin
|
||||
// and pressureMax, we still want this recognizer to respond normally.
|
||||
if (!value.isNaN)
|
||||
value = value.clamp(0.0, 1.0);
|
||||
value = clampDouble(value, 0.0, 1.0);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import 'dart:math' as math show pi;
|
||||
import 'dart:ui' as ui show Paint, Path, Canvas;
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
// This package is split into multiple parts to enable a private API that is
|
||||
|
||||
@ -161,7 +161,7 @@ class _AnimatedIconPainter extends CustomPainter {
|
||||
}
|
||||
canvas.scale(scale, scale);
|
||||
|
||||
final double clampedProgress = progress.value.clamp(0.0, 1.0);
|
||||
final double clampedProgress = clampDouble(progress.value, 0.0, 1.0);
|
||||
for (final _PathFrames path in paths)
|
||||
path.paint(canvas, color, uiPathFactory, clampedProgress);
|
||||
}
|
||||
|
||||
@ -1263,7 +1263,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
final bool isScrolledUnder = overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent);
|
||||
final bool isPinnedWithOpacityFade = pinned && floating && bottom != null && extraToolbarHeight == 0.0;
|
||||
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight)).clamp(0.0, 1.0)
|
||||
? clampDouble(visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight), 0.0, 1.0)
|
||||
: 1.0;
|
||||
|
||||
final Widget appBar = FlexibleSpaceBar.createSettings(
|
||||
@ -1300,7 +1300,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
titleSpacing: titleSpacing,
|
||||
shape: shape,
|
||||
toolbarOpacity: toolbarOpacity,
|
||||
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)),
|
||||
bottomOpacity: pinned ? 1.0 : clampDouble(visibleMainHeight / _bottomHeight, 0.0, 1.0),
|
||||
toolbarHeight: toolbarHeight,
|
||||
leadingWidth: leadingWidth,
|
||||
backwardsCompatibility: backwardsCompatibility,
|
||||
|
||||
@ -365,7 +365,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> with MaterialStat
|
||||
right: densityAdjustment.dx,
|
||||
bottom: densityAdjustment.dy,
|
||||
),
|
||||
).clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity);
|
||||
).clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity); // ignore_clamp_double_lint
|
||||
|
||||
|
||||
final Widget result = ConstrainedBox(
|
||||
|
||||
@ -302,7 +302,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with MaterialStateMixin
|
||||
final double dx = math.max(0, densityAdjustment.dx);
|
||||
final EdgeInsetsGeometry padding = resolvedPadding!
|
||||
.add(EdgeInsets.fromLTRB(dx, dy, dx, dy))
|
||||
.clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity);
|
||||
.clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity); // ignore_clamp_double_lint
|
||||
|
||||
// If an opaque button's background is becoming translucent while its
|
||||
// elevation is changing, change the elevation first. Material implicitly
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@ -1111,7 +1112,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
|
||||
final EdgeInsetsGeometry defaultLabelPadding = EdgeInsets.lerp(
|
||||
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
(MediaQuery.of(context).textScaleFactor - 1.0).clamp(0.0, 1.0),
|
||||
clampDouble(MediaQuery.of(context).textScaleFactor - 1.0, 0.0, 1.0),
|
||||
)!;
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -153,7 +154,7 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect
|
||||
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final Offset midpointAnchor = Offset(
|
||||
(widget.selectionMidpoint.dx - widget.globalEditableRegion.left).clamp(
|
||||
clampDouble(widget.selectionMidpoint.dx - widget.globalEditableRegion.left,
|
||||
mediaQuery.padding.left,
|
||||
mediaQuery.size.width - mediaQuery.padding.right,
|
||||
),
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'color_scheme.dart';
|
||||
@ -1176,7 +1177,7 @@ class DialogRoute<T> extends RawDialogRoute<T> {
|
||||
}
|
||||
|
||||
double _paddingScaleFactor(double textScaleFactor) {
|
||||
final double clampedTextScaleFactor = textScaleFactor.clamp(1.0, 2.0);
|
||||
final double clampedTextScaleFactor = clampDouble(textScaleFactor, 1.0, 2.0);
|
||||
// The final padding scale factor is clamped between 1/3 and 1. For example,
|
||||
// a non-scaled padding of 24 will produce a padding between 24 and 8.
|
||||
return lerpDouble(1.0, 1.0 / 3.0, clampedTextScaleFactor - 1.0)!;
|
||||
|
||||
@ -67,12 +67,12 @@ class _DropdownMenuPainter extends CustomPainter {
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final double selectedItemOffset = getSelectedItemOffset();
|
||||
final Tween<double> top = Tween<double>(
|
||||
begin: selectedItemOffset.clamp(0.0, math.max(size.height - _kMenuItemHeight, 0.0)),
|
||||
begin: clampDouble(selectedItemOffset, 0.0, math.max(size.height - _kMenuItemHeight, 0.0)),
|
||||
end: 0.0,
|
||||
);
|
||||
|
||||
final Tween<double> bottom = Tween<double>(
|
||||
begin: (top.begin! + _kMenuItemHeight).clamp(math.min(_kMenuItemHeight, size.height), size.height),
|
||||
begin: clampDouble(top.begin! + _kMenuItemHeight, math.min(_kMenuItemHeight, size.height), size.height),
|
||||
end: size.height,
|
||||
);
|
||||
|
||||
@ -166,8 +166,8 @@ class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>>
|
||||
if (widget.itemIndex == widget.route.selectedIndex) {
|
||||
opacity = CurvedAnimation(parent: widget.route.animation!, curve: const Threshold(0.0));
|
||||
} else {
|
||||
final double start = (0.5 + (widget.itemIndex + 1) * unit).clamp(0.0, 1.0);
|
||||
final double end = (start + 1.5 * unit).clamp(0.0, 1.0);
|
||||
final double start = clampDouble(0.5 + (widget.itemIndex + 1) * unit, 0.0, 1.0);
|
||||
final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0);
|
||||
opacity = CurvedAnimation(parent: widget.route.animation!, curve: Interval(start, end));
|
||||
}
|
||||
Widget child = Container(
|
||||
@ -371,10 +371,10 @@ class _DropdownMenuRouteLayout<T> extends SingleChildLayoutDelegate {
|
||||
final double left;
|
||||
switch (textDirection!) {
|
||||
case TextDirection.rtl:
|
||||
left = buttonRect.right.clamp(0.0, size.width) - childSize.width;
|
||||
left = clampDouble(buttonRect.right, 0.0, size.width) - childSize.width;
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
left = buttonRect.left.clamp(0.0, size.width - childSize.width);
|
||||
left = clampDouble(buttonRect.left, 0.0, size.width - childSize.width);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
@ -231,7 +232,7 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
|
||||
|
||||
// 0.0 -> Expanded
|
||||
// 1.0 -> Collapsed to toolbar
|
||||
final double t = (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent).clamp(0.0, 1.0);
|
||||
final double t = clampDouble(1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent, 0.0, 1.0);
|
||||
|
||||
// background
|
||||
if (widget.background != null) {
|
||||
@ -307,7 +308,10 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
|
||||
if (widget.stretchModes.contains(StretchMode.fadeTitle) &&
|
||||
constraints.maxHeight > settings.maxExtent) {
|
||||
final double stretchOpacity = 1 -
|
||||
(((constraints.maxHeight - settings.maxExtent) / 100).clamp(0.0, 1.0));
|
||||
clampDouble(
|
||||
(constraints.maxHeight - settings.maxExtent) / 100,
|
||||
0.0,
|
||||
1.0);
|
||||
title = Opacity(
|
||||
opacity: stretchOpacity,
|
||||
child: title,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// Defines the appearance of an [InputDecorator]'s border.
|
||||
@ -418,7 +419,7 @@ class OutlineInputBorder extends InputBorder {
|
||||
// Currently, BorderRadius only supports circular radii.
|
||||
const double cornerArcSweep = math.pi / 2.0;
|
||||
final double tlCornerArcSweep = math.acos(
|
||||
(1 - start / scaledRRect.tlRadiusX).clamp(0.0, 1.0),
|
||||
clampDouble(1 - start / scaledRRect.tlRadiusX, 0.0, 1.0),
|
||||
);
|
||||
|
||||
final Path path = Path()
|
||||
@ -436,7 +437,7 @@ class OutlineInputBorder extends InputBorder {
|
||||
} else if (start + extent < scaledRRect.width) {
|
||||
final double dx = scaledRRect.width - (start + extent);
|
||||
final double sweep = math.asin(
|
||||
(1 - dx / scaledRRect.trRadiusX).clamp(0.0, 1.0),
|
||||
clampDouble(1 - dx / scaledRRect.trRadiusX, 0.0, 1.0),
|
||||
);
|
||||
path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'color_scheme.dart';
|
||||
@ -918,7 +919,7 @@ class _ClampTextScaleFactor extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaleFactor: MediaQuery.of(context).textScaleFactor.clamp(
|
||||
textScaleFactor: clampDouble(MediaQuery.of(context).textScaleFactor,
|
||||
0.0,
|
||||
upperLimit,
|
||||
),
|
||||
|
||||
@ -543,7 +543,7 @@ class _PopupMenu<T> extends StatelessWidget {
|
||||
|
||||
for (int i = 0; i < route.items.length; i += 1) {
|
||||
final double start = (i + 1) * unit;
|
||||
final double end = (start + 1.5 * unit).clamp(0.0, 1.0);
|
||||
final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0);
|
||||
final CurvedAnimation opacity = CurvedAnimation(
|
||||
parent: route.animation!,
|
||||
curve: Interval(start, end),
|
||||
|
||||
@ -202,7 +202,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
drawBar(0.0, value!.clamp(0.0, 1.0) * size.width);
|
||||
drawBar(0.0, clampDouble(value!, 0.0, 1.0) * size.width);
|
||||
} else {
|
||||
final double x1 = size.width * line1Tail.transform(animationValue);
|
||||
final double width1 = size.width * line1Head.transform(animationValue) - x1;
|
||||
@ -385,7 +385,7 @@ class _CircularProgressIndicatorPainter extends CustomPainter {
|
||||
? _startAngle
|
||||
: _startAngle + tailValue * 3 / 2 * math.pi + rotationValue * math.pi * 2.0 + offsetValue * 0.5 * math.pi,
|
||||
arcSweep = value != null
|
||||
? value.clamp(0.0, 1.0) * _sweep
|
||||
? clampDouble(value, 0.0, 1.0) * _sweep
|
||||
: math.max(headValue * 3 / 2 * math.pi - tailValue * 3 / 2 * math.pi, _epsilon);
|
||||
|
||||
final Color? backgroundColor;
|
||||
|
||||
@ -1079,7 +1079,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
|
||||
}
|
||||
|
||||
double _discretize(double value) {
|
||||
double result = value.clamp(0.0, 1.0);
|
||||
double result = clampDouble(value, 0.0, 1.0);
|
||||
if (isDiscrete) {
|
||||
result = (result * divisions!).round() / divisions!;
|
||||
}
|
||||
@ -1092,7 +1092,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
|
||||
|
||||
void _startInteraction(Offset globalPosition) {
|
||||
_state.showValueIndicator();
|
||||
final double tapValue = _getValueFromGlobalPosition(globalPosition).clamp(0.0, 1.0);
|
||||
final double tapValue = clampDouble(_getValueFromGlobalPosition(globalPosition), 0.0, 1.0);
|
||||
_lastThumbSelection = sliderTheme.thumbSelector!(textDirection, values, tapValue, _thumbSize, size, 0);
|
||||
|
||||
if (_lastThumbSelection != null) {
|
||||
@ -1613,11 +1613,11 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
|
||||
}
|
||||
|
||||
double get _decreasedStartValue {
|
||||
return (values.start - _semanticActionUnit).clamp(0.0, 1.0);
|
||||
return clampDouble(values.start - _semanticActionUnit, 0.0, 1.0);
|
||||
}
|
||||
|
||||
double get _increasedEndValue {
|
||||
return (values.end + _semanticActionUnit).clamp(0.0, 1.0);
|
||||
return clampDouble(values.end + _semanticActionUnit, 0.0, 1.0);
|
||||
}
|
||||
|
||||
double get _decreasedEndValue {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'debug.dart';
|
||||
@ -409,7 +410,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
|
||||
double newValue = _dragOffset! / (containerExtent * _kDragContainerExtentPercentage);
|
||||
if (_mode == _RefreshIndicatorMode.armed)
|
||||
newValue = math.max(newValue, 1.0 / _kDragSizeFactorLimit);
|
||||
_positionController.value = newValue.clamp(0.0, 1.0); // this triggers various rebuilds
|
||||
_positionController.value = clampDouble(newValue, 0.0, 1.0); // this triggers various rebuilds
|
||||
if (_mode == _RefreshIndicatorMode.drag && _valueColor.value!.alpha == 0xFF)
|
||||
_mode = _RefreshIndicatorMode.armed;
|
||||
}
|
||||
|
||||
@ -993,7 +993,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
|
||||
|
||||
if (extendBody) {
|
||||
bodyMaxHeight += bottomWidgetsHeight;
|
||||
bodyMaxHeight = bodyMaxHeight.clamp(0.0, looseConstraints.maxHeight - contentTop);
|
||||
bodyMaxHeight = clampDouble(bodyMaxHeight, 0.0, looseConstraints.maxHeight - contentTop);
|
||||
assert(bodyMaxHeight <= math.max(0.0, looseConstraints.maxHeight - contentTop));
|
||||
}
|
||||
|
||||
@ -2366,7 +2366,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
|
||||
/// [Scaffold.floatingActionButton]. This value must not be null.
|
||||
set _floatingActionButtonVisibilityValue(double newValue) {
|
||||
assert(newValue != null);
|
||||
_floatingActionButtonVisibilityController.value = newValue.clamp(
|
||||
_floatingActionButtonVisibilityController.value = clampDouble(newValue,
|
||||
_floatingActionButtonVisibilityController.lowerBound,
|
||||
_floatingActionButtonVisibilityController.upperBound,
|
||||
);
|
||||
|
||||
@ -1273,7 +1273,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
|
||||
}
|
||||
|
||||
double _discretize(double value) {
|
||||
double result = value.clamp(0.0, 1.0);
|
||||
double result = clampDouble(value, 0.0, 1.0);
|
||||
if (isDiscrete) {
|
||||
result = (result * divisions!).round() / divisions!;
|
||||
}
|
||||
@ -1540,12 +1540,12 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
|
||||
|
||||
if (semanticFormatterCallback != null) {
|
||||
config.value = semanticFormatterCallback!(_state._lerp(value));
|
||||
config.increasedValue = semanticFormatterCallback!(_state._lerp((value + _semanticActionUnit).clamp(0.0, 1.0)));
|
||||
config.decreasedValue = semanticFormatterCallback!(_state._lerp((value - _semanticActionUnit).clamp(0.0, 1.0)));
|
||||
config.increasedValue = semanticFormatterCallback!(_state._lerp(clampDouble(value + _semanticActionUnit, 0.0, 1.0)));
|
||||
config.decreasedValue = semanticFormatterCallback!(_state._lerp(clampDouble(value - _semanticActionUnit, 0.0, 1.0)));
|
||||
} else {
|
||||
config.value = '${(value * 100).round()}%';
|
||||
config.increasedValue = '${((value + _semanticActionUnit).clamp(0.0, 1.0) * 100).round()}%';
|
||||
config.decreasedValue = '${((value - _semanticActionUnit).clamp(0.0, 1.0) * 100).round()}%';
|
||||
config.increasedValue = '${(clampDouble(value + _semanticActionUnit, 0.0, 1.0) * 100).round()}%';
|
||||
config.decreasedValue = '${(clampDouble(value - _semanticActionUnit, 0.0, 1.0) * 100).round()}%';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1553,13 +1553,13 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
|
||||
|
||||
void increaseAction() {
|
||||
if (isInteractive) {
|
||||
onChanged!((value + _semanticActionUnit).clamp(0.0, 1.0));
|
||||
onChanged!(clampDouble(value + _semanticActionUnit, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
void decreaseAction() {
|
||||
if (isInteractive) {
|
||||
onChanged!((value - _semanticActionUnit).clamp(0.0, 1.0));
|
||||
onChanged!(clampDouble(value - _semanticActionUnit, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3180,7 +3180,7 @@ class _PaddleSliderValueIndicatorPathPainter {
|
||||
// factor of the value indicator.
|
||||
final double neckStretchBaseline = math.max(0.0, rightBottomNeckCenterY - math.max(leftTopNeckCenter.dy, neckRightCenter.dy));
|
||||
final double t = math.pow(inverseTextScale, 3.0) as double;
|
||||
final double stretch = (neckStretchBaseline * t).clamp(0.0, 10.0 * neckStretchBaseline);
|
||||
final double stretch = clampDouble(neckStretchBaseline * t, 0.0, 10.0 * neckStretchBaseline);
|
||||
final Offset neckStretch = Offset(0.0, neckStretchBaseline - stretch);
|
||||
|
||||
assert(!_debuggingLabelLocation || () {
|
||||
|
||||
@ -311,7 +311,7 @@ double _indexChangeProgress(TabController controller) {
|
||||
// The controller's offset is changing because the user is dragging the
|
||||
// TabBarView's PageView to the left or right.
|
||||
if (!controller.indexIsChanging)
|
||||
return (currentIndex - controllerValue).abs().clamp(0.0, 1.0);
|
||||
return clampDouble((currentIndex - controllerValue).abs(), 0.0, 1.0);
|
||||
|
||||
// The TabController animation's value is changing from previousIndex to currentIndex.
|
||||
return (controllerValue - currentIndex).abs() / (currentIndex - previousIndex).abs();
|
||||
@ -417,8 +417,8 @@ class _IndicatorPainter extends CustomPainter {
|
||||
final double index = controller.index.toDouble();
|
||||
final double value = controller.animation!.value;
|
||||
final bool ltr = index > value;
|
||||
final int from = (ltr ? value.floor() : value.ceil()).clamp(0, maxTabIndex);
|
||||
final int to = (ltr ? from + 1 : from - 1).clamp(0, maxTabIndex);
|
||||
final int from = (ltr ? value.floor() : value.ceil()).clamp(0, maxTabIndex); // ignore_clamp_double_lint
|
||||
final int to = (ltr ? from + 1 : from - 1).clamp(0, maxTabIndex); // ignore_clamp_double_lint
|
||||
final Rect fromRect = indicatorRect(size, from);
|
||||
final Rect toRect = indicatorRect(size, to);
|
||||
_currentRect = Rect.lerp(fromRect, toRect, (value - from).abs());
|
||||
@ -491,8 +491,8 @@ class _DragAnimation extends Animation<double> with AnimationWithParentMixin<dou
|
||||
double get value {
|
||||
assert(!controller.indexIsChanging);
|
||||
final double controllerMaxValue = (controller.length - 1).toDouble();
|
||||
final double controllerValue = controller.animation!.value.clamp(0.0, controllerMaxValue);
|
||||
return (controllerValue - index.toDouble()).abs().clamp(0.0, 1.0);
|
||||
final double controllerValue = clampDouble(controller.animation!.value, 0.0, controllerMaxValue);
|
||||
return clampDouble((controllerValue - index.toDouble()).abs(), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1048,7 +1048,7 @@ class _TabBarState extends State<TabBar> {
|
||||
case TextDirection.ltr:
|
||||
break;
|
||||
}
|
||||
return (tabCenter - viewportWidth / 2.0).clamp(minExtent, maxExtent);
|
||||
return clampDouble(tabCenter - viewportWidth / 2.0, minExtent, maxExtent);
|
||||
}
|
||||
|
||||
double _tabCenteredScrollOffset(int index) {
|
||||
@ -1510,12 +1510,12 @@ class _TabBarViewState extends State<TabBarView> {
|
||||
_controller!.index = _pageController.page!.round();
|
||||
_currentIndex =_controller!.index;
|
||||
}
|
||||
_controller!.offset = (_pageController.page! - _controller!.index).clamp(-1.0, 1.0);
|
||||
_controller!.offset = clampDouble(_pageController.page! - _controller!.index, -1.0, 1.0);
|
||||
} else if (notification is ScrollEndNotification) {
|
||||
_controller!.index = _pageController.page!.round();
|
||||
_currentIndex = _controller!.index;
|
||||
if (!_controller!.indexIsChanging)
|
||||
_controller!.offset = (_pageController.page! - _controller!.index).clamp(-1.0, 1.0);
|
||||
_controller!.offset = clampDouble(_pageController.page! - _controller!.index, -1.0, 1.0);
|
||||
}
|
||||
_warpUnderwayCount -= 1;
|
||||
|
||||
|
||||
@ -898,7 +898,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
|
||||
if (widget.maxLength! > 0) {
|
||||
// Show the maxLength in the counter
|
||||
counterText += '/${widget.maxLength}';
|
||||
final int remaining = (widget.maxLength! - currentLength).clamp(0, widget.maxLength!);
|
||||
final int remaining = (widget.maxLength! - currentLength).clamp(0, widget.maxLength!); // ignore_clamp_double_lint
|
||||
semanticCounterText = localizations.remainingTextFieldCharacterCount(remaining);
|
||||
}
|
||||
|
||||
|
||||
@ -2686,8 +2686,8 @@ class VisualDensity with Diagnosticable {
|
||||
BoxConstraints effectiveConstraints(BoxConstraints constraints) {
|
||||
assert(constraints != null && constraints.debugAssertIsValid());
|
||||
return constraints.copyWith(
|
||||
minWidth: (constraints.minWidth + baseSizeAdjustment.dx).clamp(0.0, constraints.maxWidth),
|
||||
minHeight: (constraints.minHeight + baseSizeAdjustment.dy).clamp(0.0, constraints.maxHeight),
|
||||
minWidth: clampDouble(constraints.minWidth + baseSizeAdjustment.dx, 0.0, constraints.maxWidth),
|
||||
minHeight: clampDouble(constraints.minHeight + baseSizeAdjustment.dy, 0.0, constraints.maxHeight),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -206,10 +206,10 @@ class HSVColor {
|
||||
if (b == null)
|
||||
return a._scaleAlpha(1.0 - t);
|
||||
return HSVColor.fromAHSV(
|
||||
lerpDouble(a.alpha, b.alpha, t)!.clamp(0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.alpha, b.alpha, t)!, 0.0, 1.0),
|
||||
lerpDouble(a.hue, b.hue, t)! % 360.0,
|
||||
lerpDouble(a.saturation, b.saturation, t)!.clamp(0.0, 1.0),
|
||||
lerpDouble(a.value, b.value, t)!.clamp(0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.saturation, b.saturation, t)!, 0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.value, b.value, t)!, 0.0, 1.0),
|
||||
);
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ class HSLColor {
|
||||
// Saturation can exceed 1.0 with rounding errors, so clamp it.
|
||||
final double saturation = lightness == 1.0
|
||||
? 0.0
|
||||
: ((delta / (1.0 - (2.0 * lightness - 1.0).abs())).clamp(0.0, 1.0));
|
||||
: clampDouble(delta / (1.0 - (2.0 * lightness - 1.0).abs()), 0.0, 1.0);
|
||||
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
|
||||
}
|
||||
|
||||
@ -390,10 +390,10 @@ class HSLColor {
|
||||
if (b == null)
|
||||
return a._scaleAlpha(1.0 - t);
|
||||
return HSLColor.fromAHSL(
|
||||
lerpDouble(a.alpha, b.alpha, t)!.clamp(0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.alpha, b.alpha, t)!, 0.0, 1.0),
|
||||
lerpDouble(a.hue, b.hue, t)! % 360.0,
|
||||
lerpDouble(a.saturation, b.saturation, t)!.clamp(0.0, 1.0),
|
||||
lerpDouble(a.lightness, b.lightness, t)!.clamp(0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.saturation, b.saturation, t)!, 0.0, 1.0),
|
||||
clampDouble(lerpDouble(a.lightness, b.lightness, t)!, 0.0, 1.0),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -161,12 +161,12 @@ abstract class EdgeInsetsGeometry {
|
||||
/// or equal to `min`, and less than or equal to `max`.
|
||||
EdgeInsetsGeometry clamp(EdgeInsetsGeometry min, EdgeInsetsGeometry max) {
|
||||
return _MixedEdgeInsets.fromLRSETB(
|
||||
_left.clamp(min._left, max._left),
|
||||
_right.clamp(min._right, max._right),
|
||||
_start.clamp(min._start, max._start),
|
||||
_end.clamp(min._end, max._end),
|
||||
_top.clamp(min._top, max._top),
|
||||
_bottom.clamp(min._bottom, max._bottom),
|
||||
clampDouble(_left, min._left, max._left),
|
||||
clampDouble(_right, min._right, max._right),
|
||||
clampDouble(_start, min._start, max._start),
|
||||
clampDouble(_end, min._end, max._end),
|
||||
clampDouble(_top, min._top, max._top),
|
||||
clampDouble(_bottom, min._bottom, max._bottom),
|
||||
);
|
||||
}
|
||||
|
||||
@ -505,10 +505,10 @@ class EdgeInsets extends EdgeInsetsGeometry {
|
||||
@override
|
||||
EdgeInsetsGeometry clamp(EdgeInsetsGeometry min, EdgeInsetsGeometry max) {
|
||||
return EdgeInsets.fromLTRB(
|
||||
_left.clamp(min._left, max._left),
|
||||
_top.clamp(min._top, max._top),
|
||||
_right.clamp(min._right, max._right),
|
||||
_bottom.clamp(min._bottom, max._bottom),
|
||||
clampDouble(_left, min._left, max._left),
|
||||
clampDouble(_top, min._top, max._top),
|
||||
clampDouble(_right, min._right, max._right),
|
||||
clampDouble(_bottom, min._bottom, max._bottom),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ class FlutterLogoDecoration extends Decoration {
|
||||
b.style,
|
||||
b.margin * t,
|
||||
b._position,
|
||||
b._opacity * t.clamp(0.0, 1.0),
|
||||
b._opacity * clampDouble(t, 0.0, 1.0),
|
||||
);
|
||||
}
|
||||
if (b == null) {
|
||||
@ -128,7 +128,7 @@ class FlutterLogoDecoration extends Decoration {
|
||||
a.style,
|
||||
a.margin * t,
|
||||
a._position,
|
||||
a._opacity * (1.0 - t).clamp(0.0, 1.0),
|
||||
a._opacity * clampDouble(1.0 - t, 0.0, 1.0),
|
||||
);
|
||||
}
|
||||
if (t == 0.0)
|
||||
@ -140,7 +140,7 @@ class FlutterLogoDecoration extends Decoration {
|
||||
t < 0.5 ? a.style : b.style,
|
||||
EdgeInsets.lerp(a.margin, b.margin, t)!,
|
||||
a._position + (b._position - a._position) * t,
|
||||
(a._opacity + (b._opacity - a._opacity) * t).clamp(0.0, 1.0),
|
||||
clampDouble(a._opacity + (b._opacity - a._opacity) * t, 0.0, 1.0),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'basic_types.dart';
|
||||
|
||||
/// Position a child box within a container box, either above or below a target
|
||||
@ -64,7 +65,7 @@ Offset positionDependentBox({
|
||||
if (size.width - margin * 2.0 < childSize.width) {
|
||||
x = (size.width - childSize.width) / 2.0;
|
||||
} else {
|
||||
final double normalizedTargetX = target.dx.clamp(margin, size.width - margin);
|
||||
final double normalizedTargetX = clampDouble(target.dx, margin, size.width - margin);
|
||||
final double edge = margin + childSize.width / 2.0;
|
||||
if (normalizedTargetX < edge) {
|
||||
x = margin;
|
||||
|
||||
@ -621,7 +621,7 @@ class TextPainter {
|
||||
newWidth = maxIntrinsicWidth;
|
||||
break;
|
||||
}
|
||||
newWidth = newWidth.clamp(minWidth, maxWidth);
|
||||
newWidth = clampDouble(newWidth, minWidth, maxWidth);
|
||||
if (newWidth != _applyFloatingPointHack(_paragraph!.width)) {
|
||||
_paragraph!.layout(ui.ParagraphConstraints(width: newWidth));
|
||||
}
|
||||
@ -781,7 +781,8 @@ class TextPainter {
|
||||
|
||||
final double caretEnd = box.end;
|
||||
final double dx = box.direction == TextDirection.rtl ? caretEnd - caretPrototype.width : caretEnd;
|
||||
return Rect.fromLTRB(dx.clamp(0, _paragraph!.width), box.top, dx.clamp(0, _paragraph!.width), box.bottom);
|
||||
return Rect.fromLTRB(clampDouble(dx, 0, _paragraph!.width), box.top,
|
||||
clampDouble(dx, 0, _paragraph!.width), box.bottom);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -823,7 +824,7 @@ class TextPainter {
|
||||
final TextBox box = boxes.last;
|
||||
final double caretStart = box.start;
|
||||
final double dx = box.direction == TextDirection.rtl ? caretStart - caretPrototype.width : caretStart;
|
||||
return Rect.fromLTRB(dx.clamp(0, _paragraph!.width), box.top, dx.clamp(0, _paragraph!.width), box.bottom);
|
||||
return Rect.fromLTRB(clampDouble(dx, 0, _paragraph!.width), box.top, clampDouble(dx, 0, _paragraph!.width), box.bottom);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -967,7 +967,7 @@ class TextStyle with Diagnosticable {
|
||||
fontFamily: fontFamily ?? _fontFamily,
|
||||
fontFamilyFallback: fontFamilyFallback ?? this.fontFamilyFallback,
|
||||
fontSize: fontSize == null ? null : fontSize! * fontSizeFactor + fontSizeDelta,
|
||||
fontWeight: fontWeight == null ? null : FontWeight.values[(fontWeight!.index + fontWeightDelta).clamp(0, FontWeight.values.length - 1)],
|
||||
fontWeight: fontWeight == null ? null : FontWeight.values[(fontWeight!.index + fontWeightDelta).clamp(0, FontWeight.values.length - 1)], // ignore_clamp_double_lint
|
||||
fontStyle: fontStyle ?? this.fontStyle,
|
||||
letterSpacing: letterSpacing == null ? null : letterSpacing! * letterSpacingFactor + letterSpacingDelta,
|
||||
wordSpacing: wordSpacing == null ? null : wordSpacing! * wordSpacingFactor + wordSpacingDelta,
|
||||
|
||||
@ -55,10 +55,10 @@ class ClampedSimulation extends Simulation {
|
||||
final double dxMax;
|
||||
|
||||
@override
|
||||
double x(double time) => simulation.x(time).clamp(xMin, xMax);
|
||||
double x(double time) => clampDouble(simulation.x(time), xMin, xMax);
|
||||
|
||||
@override
|
||||
double dx(double time) => simulation.dx(time).clamp(dxMin, dxMax);
|
||||
double dx(double time) => clampDouble(simulation.dx(time), dxMin, dxMax);
|
||||
|
||||
@override
|
||||
bool isDone(double time) => simulation.isDone(time);
|
||||
|
||||
@ -115,14 +115,14 @@ class BoundedFrictionSimulation extends FrictionSimulation {
|
||||
super.velocity,
|
||||
this._minX,
|
||||
this._maxX,
|
||||
) : assert(position.clamp(_minX, _maxX) == position);
|
||||
) : assert(clampDouble(position, _minX, _maxX) == position);
|
||||
|
||||
final double _minX;
|
||||
final double _maxX;
|
||||
|
||||
@override
|
||||
double x(double time) {
|
||||
return super.x(time).clamp(_minX, _maxX);
|
||||
return clampDouble(super.x(time), _minX, _maxX);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -212,10 +212,10 @@ class BoxConstraints extends Constraints {
|
||||
/// as close as possible to the original constraints.
|
||||
BoxConstraints enforce(BoxConstraints constraints) {
|
||||
return BoxConstraints(
|
||||
minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth),
|
||||
maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth),
|
||||
minHeight: minHeight.clamp(constraints.minHeight, constraints.maxHeight),
|
||||
maxHeight: maxHeight.clamp(constraints.minHeight, constraints.maxHeight),
|
||||
minWidth: clampDouble(minWidth, constraints.minWidth, constraints.maxWidth),
|
||||
maxWidth: clampDouble(maxWidth, constraints.minWidth, constraints.maxWidth),
|
||||
minHeight: clampDouble(minHeight, constraints.minHeight, constraints.maxHeight),
|
||||
maxHeight: clampDouble(maxHeight, constraints.minHeight, constraints.maxHeight),
|
||||
);
|
||||
}
|
||||
|
||||
@ -224,10 +224,10 @@ class BoxConstraints extends Constraints {
|
||||
/// box constraints.
|
||||
BoxConstraints tighten({ double? width, double? height }) {
|
||||
return BoxConstraints(
|
||||
minWidth: width == null ? minWidth : width.clamp(minWidth, maxWidth),
|
||||
maxWidth: width == null ? maxWidth : width.clamp(minWidth, maxWidth),
|
||||
minHeight: height == null ? minHeight : height.clamp(minHeight, maxHeight),
|
||||
maxHeight: height == null ? maxHeight : height.clamp(minHeight, maxHeight),
|
||||
minWidth: width == null ? minWidth : clampDouble(width, minWidth, maxWidth),
|
||||
maxWidth: width == null ? maxWidth : clampDouble(width, minWidth, maxWidth),
|
||||
minHeight: height == null ? minHeight : clampDouble(height, minHeight, maxHeight),
|
||||
maxHeight: height == null ? maxHeight : clampDouble(height, minHeight, maxHeight),
|
||||
);
|
||||
}
|
||||
|
||||
@ -253,14 +253,14 @@ class BoxConstraints extends Constraints {
|
||||
/// possible to the given width.
|
||||
double constrainWidth([ double width = double.infinity ]) {
|
||||
assert(debugAssertIsValid());
|
||||
return width.clamp(minWidth, maxWidth);
|
||||
return clampDouble(width, minWidth, maxWidth);
|
||||
}
|
||||
|
||||
/// Returns the height that both satisfies the constraints and is as close as
|
||||
/// possible to the given height.
|
||||
double constrainHeight([ double height = double.infinity ]) {
|
||||
assert(debugAssertIsValid());
|
||||
return height.clamp(minHeight, maxHeight);
|
||||
return clampDouble(height, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
Size _debugPropagateDebugSize(Size size, Size result) {
|
||||
|
||||
@ -1651,8 +1651,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
|
||||
final Offset start = Offset(0.0, preferredLineHeight) + caretOffset + paintOffset;
|
||||
return <TextSelectionPoint>[TextSelectionPoint(start, null)];
|
||||
} else {
|
||||
final Offset start = Offset(boxes.first.start.clamp(0, _textPainter.size.width), boxes.first.bottom) + paintOffset;
|
||||
final Offset end = Offset(boxes.last.end.clamp(0, _textPainter.size.width), boxes.last.bottom) + paintOffset;
|
||||
final Offset start = Offset(clampDouble(boxes.first.start, 0, _textPainter.size.width), boxes.first.bottom) + paintOffset;
|
||||
final Offset end = Offset(clampDouble(boxes.last.end, 0, _textPainter.size.width), boxes.last.bottom) + paintOffset;
|
||||
return <TextSelectionPoint>[
|
||||
TextSelectionPoint(start, boxes.first.direction),
|
||||
TextSelectionPoint(end, boxes.last.direction),
|
||||
@ -2480,8 +2480,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
|
||||
void _paintHandleLayers(PaintingContext context, List<TextSelectionPoint> endpoints) {
|
||||
Offset startPoint = endpoints[0].point;
|
||||
startPoint = Offset(
|
||||
startPoint.dx.clamp(0.0, size.width),
|
||||
startPoint.dy.clamp(0.0, size.height),
|
||||
clampDouble(startPoint.dx, 0.0, size.width),
|
||||
clampDouble(startPoint.dy, 0.0, size.height),
|
||||
);
|
||||
context.pushLayer(
|
||||
LeaderLayer(link: startHandleLayerLink, offset: startPoint),
|
||||
@ -2491,8 +2491,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
|
||||
if (endpoints.length == 2) {
|
||||
Offset endPoint = endpoints[1].point;
|
||||
endPoint = Offset(
|
||||
endPoint.dx.clamp(0.0, size.width),
|
||||
endPoint.dy.clamp(0.0, size.height),
|
||||
clampDouble(endPoint.dx, 0.0, size.width),
|
||||
clampDouble(endPoint.dy, 0.0, size.height),
|
||||
);
|
||||
context.pushLayer(
|
||||
LeaderLayer(link: endHandleLayerLink, offset: endPoint),
|
||||
|
||||
@ -1337,7 +1337,7 @@ abstract class RenderSliver extends RenderObject {
|
||||
final double a = constraints.scrollOffset;
|
||||
final double b = constraints.scrollOffset + constraints.remainingPaintExtent;
|
||||
// the clamp on the next line is to avoid floating point rounding errors
|
||||
return (to.clamp(a, b) - from.clamp(a, b)).clamp(0.0, constraints.remainingPaintExtent);
|
||||
return clampDouble(clampDouble(to, a, b) - clampDouble(from, a, b), 0.0, constraints.remainingPaintExtent);
|
||||
}
|
||||
|
||||
/// Computes the portion of the region from `from` to `to` that is within
|
||||
@ -1353,7 +1353,7 @@ abstract class RenderSliver extends RenderObject {
|
||||
final double a = constraints.scrollOffset + constraints.cacheOrigin;
|
||||
final double b = constraints.scrollOffset + constraints.remainingCacheExtent;
|
||||
// the clamp on the next line is to avoid floating point rounding errors
|
||||
return (to.clamp(a, b) - from.clamp(a, b)).clamp(0.0, constraints.remainingCacheExtent);
|
||||
return clampDouble(clampDouble(to, a, b) - clampDouble(from, a, b), 0.0, constraints.remainingCacheExtent);
|
||||
}
|
||||
|
||||
/// Returns the distance from the leading _visible_ edge of the sliver to the
|
||||
|
||||
@ -570,10 +570,10 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
|
||||
if (firstChild != null) {
|
||||
final int oldFirstIndex = indexOf(firstChild!);
|
||||
final int oldLastIndex = indexOf(lastChild!);
|
||||
final int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, childCount);
|
||||
final int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, childCount); // ignore_clamp_double_lint
|
||||
final int trailingGarbage = targetLastIndex == null
|
||||
? 0
|
||||
: (oldLastIndex - targetLastIndex).clamp(0, childCount);
|
||||
: (oldLastIndex - targetLastIndex).clamp(0, childCount); // ignore_clamp_double_lint
|
||||
collectGarbage(leadingGarbage, trailingGarbage);
|
||||
} else {
|
||||
collectGarbage(0, 0);
|
||||
|
||||
@ -364,7 +364,7 @@ abstract class RenderSliverScrollingPersistentHeader extends RenderSliverPersist
|
||||
geometry = SliverGeometry(
|
||||
scrollExtent: maxExtent,
|
||||
paintOrigin: math.min(constraints.overlap, 0.0),
|
||||
paintExtent: paintExtent.clamp(0.0, constraints.remainingPaintExtent),
|
||||
paintExtent: clampDouble(paintExtent, 0.0, constraints.remainingPaintExtent),
|
||||
maxPaintExtent: maxExtent + stretchOffset,
|
||||
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
|
||||
);
|
||||
@ -381,7 +381,7 @@ abstract class RenderSliverScrollingPersistentHeader extends RenderSliverPersist
|
||||
geometry = SliverGeometry(
|
||||
scrollExtent: maxExtent,
|
||||
paintOrigin: math.min(constraints.overlap, 0.0),
|
||||
paintExtent: paintExtent.clamp(0.0, constraints.remainingPaintExtent),
|
||||
paintExtent: clampDouble(paintExtent, 0.0, constraints.remainingPaintExtent),
|
||||
maxPaintExtent: maxExtent,
|
||||
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
|
||||
);
|
||||
@ -423,7 +423,7 @@ abstract class RenderSliverPinnedPersistentHeader extends RenderSliverPersistent
|
||||
final bool overlapsContent = constraints.overlap > 0.0;
|
||||
layoutChild(constraints.scrollOffset, maxExtent, overlapsContent: overlapsContent);
|
||||
final double effectiveRemainingPaintExtent = math.max(0, constraints.remainingPaintExtent - constraints.overlap);
|
||||
final double layoutExtent = (maxExtent - constraints.scrollOffset).clamp(0.0, effectiveRemainingPaintExtent);
|
||||
final double layoutExtent = clampDouble(maxExtent - constraints.scrollOffset, 0.0, effectiveRemainingPaintExtent);
|
||||
final double stretchOffset = stretchConfiguration != null ?
|
||||
constraints.overlap.abs() :
|
||||
0.0;
|
||||
@ -595,8 +595,8 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste
|
||||
geometry = SliverGeometry(
|
||||
scrollExtent: maxExtent,
|
||||
paintOrigin: math.min(constraints.overlap, 0.0),
|
||||
paintExtent: paintExtent.clamp(0.0, constraints.remainingPaintExtent),
|
||||
layoutExtent: layoutExtent.clamp(0.0, constraints.remainingPaintExtent),
|
||||
paintExtent: clampDouble(paintExtent, 0.0, constraints.remainingPaintExtent),
|
||||
layoutExtent: clampDouble(layoutExtent, 0.0, constraints.remainingPaintExtent),
|
||||
maxPaintExtent: maxExtent + stretchOffset,
|
||||
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
|
||||
);
|
||||
@ -677,7 +677,7 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste
|
||||
if (delta > 0.0) // If we are trying to expand when allowFloatingExpansion is false,
|
||||
delta = 0.0; // disallow the expansion. (But allow shrinking, i.e. delta < 0.0 is fine.)
|
||||
}
|
||||
_effectiveScrollOffset = (_effectiveScrollOffset! - delta).clamp(0.0, constraints.scrollOffset);
|
||||
_effectiveScrollOffset = clampDouble(_effectiveScrollOffset! - delta, 0.0, constraints.scrollOffset);
|
||||
} else {
|
||||
_effectiveScrollOffset = constraints.scrollOffset;
|
||||
}
|
||||
@ -738,13 +738,16 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste
|
||||
// A stretch header can have a bigger childExtent than maxExtent.
|
||||
final double effectiveMaxExtent = math.max(childExtent, maxExtent);
|
||||
|
||||
targetExtent = targetExtent.clamp(
|
||||
showOnScreen.minShowOnScreenExtent,
|
||||
showOnScreen.maxShowOnScreenExtent,
|
||||
)
|
||||
// Clamp the value back to the valid range after applying additional
|
||||
// constraints. Contracting is not allowed.
|
||||
.clamp(childExtent, effectiveMaxExtent);
|
||||
targetExtent = clampDouble(
|
||||
clampDouble(
|
||||
targetExtent,
|
||||
showOnScreen.minShowOnScreenExtent,
|
||||
showOnScreen.maxShowOnScreenExtent,
|
||||
),
|
||||
// Clamp the value back to the valid range after applying additional
|
||||
// constraints. Contracting is not allowed.
|
||||
childExtent,
|
||||
effectiveMaxExtent);
|
||||
|
||||
// Expands the header if needed, with animation.
|
||||
if (targetExtent > childExtent) {
|
||||
@ -806,7 +809,7 @@ abstract class RenderSliverFloatingPinnedPersistentHeader extends RenderSliverFl
|
||||
constraints.remainingPaintExtent;
|
||||
final double maxExtent = this.maxExtent;
|
||||
final double paintExtent = maxExtent - _effectiveScrollOffset!;
|
||||
final double clampedPaintExtent = paintExtent.clamp(
|
||||
final double clampedPaintExtent = clampDouble(paintExtent,
|
||||
minAllowedExtent,
|
||||
constraints.remainingPaintExtent,
|
||||
);
|
||||
@ -818,7 +821,7 @@ abstract class RenderSliverFloatingPinnedPersistentHeader extends RenderSliverFl
|
||||
scrollExtent: maxExtent,
|
||||
paintOrigin: math.min(constraints.overlap, 0.0),
|
||||
paintExtent: clampedPaintExtent,
|
||||
layoutExtent: layoutExtent.clamp(0.0, clampedPaintExtent),
|
||||
layoutExtent: clampDouble(layoutExtent, 0.0, clampedPaintExtent),
|
||||
maxPaintExtent: maxExtent + stretchOffset,
|
||||
maxScrollObstructionExtent: minExtent,
|
||||
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
|
||||
|
||||
@ -1539,8 +1539,8 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
|
||||
// to the zero scroll offset (the line between the forward slivers and the
|
||||
// reverse slivers).
|
||||
final double centerOffset = mainAxisExtent * anchor - correctedOffset;
|
||||
final double reverseDirectionRemainingPaintExtent = centerOffset.clamp(0.0, mainAxisExtent);
|
||||
final double forwardDirectionRemainingPaintExtent = (mainAxisExtent - centerOffset).clamp(0.0, mainAxisExtent);
|
||||
final double reverseDirectionRemainingPaintExtent = clampDouble(centerOffset, 0.0, mainAxisExtent);
|
||||
final double forwardDirectionRemainingPaintExtent = clampDouble(mainAxisExtent - centerOffset, 0.0, mainAxisExtent);
|
||||
|
||||
switch (cacheExtentStyle) {
|
||||
case CacheExtentStyle.pixel:
|
||||
@ -1553,8 +1553,8 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
|
||||
|
||||
final double fullCacheExtent = mainAxisExtent + 2 * _calculatedCacheExtent!;
|
||||
final double centerCacheOffset = centerOffset + _calculatedCacheExtent!;
|
||||
final double reverseDirectionRemainingCacheExtent = centerCacheOffset.clamp(0.0, fullCacheExtent);
|
||||
final double forwardDirectionRemainingCacheExtent = (fullCacheExtent - centerCacheOffset).clamp(0.0, fullCacheExtent);
|
||||
final double reverseDirectionRemainingCacheExtent = clampDouble(centerCacheOffset, 0.0, fullCacheExtent);
|
||||
final double forwardDirectionRemainingCacheExtent = clampDouble(fullCacheExtent - centerCacheOffset, 0.0, fullCacheExtent);
|
||||
|
||||
final RenderSliver? leadingNegativeChild = childBefore(center!);
|
||||
|
||||
@ -1571,7 +1571,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
|
||||
growthDirection: GrowthDirection.reverse,
|
||||
advance: childBefore,
|
||||
remainingCacheExtent: reverseDirectionRemainingCacheExtent,
|
||||
cacheOrigin: (mainAxisExtent - centerOffset).clamp(-_calculatedCacheExtent!, 0.0),
|
||||
cacheOrigin: clampDouble(mainAxisExtent - centerOffset, -_calculatedCacheExtent!, 0.0),
|
||||
);
|
||||
if (result != 0.0)
|
||||
return -result;
|
||||
@ -1589,7 +1589,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
|
||||
growthDirection: GrowthDirection.forward,
|
||||
advance: childAfter,
|
||||
remainingCacheExtent: forwardDirectionRemainingCacheExtent,
|
||||
cacheOrigin: centerOffset.clamp(-_calculatedCacheExtent!, 0.0),
|
||||
cacheOrigin: clampDouble(centerOffset, -_calculatedCacheExtent!, 0.0),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -391,7 +391,7 @@ class FilteringTextInputFormatter extends TextInputFormatter {
|
||||
// The length added by adding the replacementString.
|
||||
final int replacedLength = originalIndex <= regionStart && originalIndex < regionEnd ? 0 : replacementString.length;
|
||||
// The length removed by removing the replacementRange.
|
||||
final int removedLength = originalIndex.clamp(regionStart, regionEnd) - regionStart;
|
||||
final int removedLength = originalIndex.clamp(regionStart, regionEnd) - regionStart; // ignore_clamp_double_lint
|
||||
return replacedLength - removedLength;
|
||||
}
|
||||
|
||||
|
||||
@ -881,7 +881,7 @@ class TextEditingValue {
|
||||
// The length added by adding the replacementString.
|
||||
final int replacedLength = originalIndex <= replacementRange.start && originalIndex < replacementRange.end ? 0 : replacementString.length;
|
||||
// The length removed by removing the replacementRange.
|
||||
final int removedLength = originalIndex.clamp(replacementRange.start, replacementRange.end) - replacementRange.start;
|
||||
final int removedLength = originalIndex.clamp(replacementRange.start, replacementRange.end) - replacementRange.start; // ignore_clamp_double_lint
|
||||
return originalIndex + replacedLength - removedLength;
|
||||
}
|
||||
|
||||
|
||||
@ -541,7 +541,7 @@ class _DraggableSheetExtent {
|
||||
/// or a user drag.
|
||||
void updateSize(double newSize, BuildContext context) {
|
||||
assert(newSize != null);
|
||||
_currentSize.value = newSize.clamp(minSize, maxSize);
|
||||
_currentSize.value = clampDouble(newSize, minSize, maxSize);
|
||||
DraggableScrollableNotification(
|
||||
minExtent: minSize,
|
||||
maxExtent: maxSize,
|
||||
@ -580,7 +580,7 @@ class _DraggableSheetExtent {
|
||||
onSizeChanged: onSizeChanged,
|
||||
// Use the possibly updated initialSize if the user hasn't dragged yet.
|
||||
currentSize: ValueNotifier<double>(hasDragged
|
||||
? _currentSize.value.clamp(minSize, maxSize)
|
||||
? clampDouble(_currentSize.value, minSize, maxSize)
|
||||
: initialSize),
|
||||
hasDragged: hasDragged,
|
||||
);
|
||||
|
||||
@ -2264,7 +2264,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
? editableSize.width / 2 - rect.center.dx
|
||||
// Valid additional offsets range from (rect.right - size.width)
|
||||
// to (rect.left). Pick the closest one if out of range.
|
||||
: 0.0.clamp(rect.right - editableSize.width, rect.left);
|
||||
: clampDouble(0.0, rect.right - editableSize.width, rect.left);
|
||||
unitOffset = const Offset(1, 0);
|
||||
} else {
|
||||
// The caret is vertically centered within the line. Expand the caret's
|
||||
@ -2278,17 +2278,17 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
|
||||
additionalOffset = expandedRect.height >= editableSize.height
|
||||
? editableSize.height / 2 - expandedRect.center.dy
|
||||
: 0.0.clamp(expandedRect.bottom - editableSize.height, expandedRect.top);
|
||||
: clampDouble(0.0, expandedRect.bottom - editableSize.height, expandedRect.top);
|
||||
unitOffset = const Offset(0, 1);
|
||||
}
|
||||
|
||||
// No overscrolling when encountering tall fonts/scripts that extend past
|
||||
// the ascent.
|
||||
final double targetOffset = (additionalOffset + _scrollController.offset)
|
||||
.clamp(
|
||||
_scrollController.position.minScrollExtent,
|
||||
_scrollController.position.maxScrollExtent,
|
||||
);
|
||||
final double targetOffset = clampDouble(
|
||||
additionalOffset + _scrollController.offset,
|
||||
_scrollController.position.minScrollExtent,
|
||||
_scrollController.position.maxScrollExtent,
|
||||
);
|
||||
|
||||
final double offsetDelta = _scrollController.offset - targetOffset;
|
||||
return RevealedOffset(rect: rect.shift(unitOffset * offsetDelta), offset: targetOffset);
|
||||
|
||||
@ -84,7 +84,7 @@ class IconThemeData with Diagnosticable {
|
||||
final Color? color;
|
||||
|
||||
/// An opacity to apply to both explicit and default icon colors.
|
||||
double? get opacity => _opacity?.clamp(0.0, 1.0);
|
||||
double? get opacity => _opacity == null ? null : clampDouble(_opacity!, 0.0, 1.0);
|
||||
final double? _opacity;
|
||||
|
||||
/// The default size for icons.
|
||||
|
||||
@ -848,7 +848,7 @@ class _AnimatedPaddingState extends AnimatedWidgetBaseState<AnimatedPadding> {
|
||||
return Padding(
|
||||
padding: _padding!
|
||||
.evaluate(animation)
|
||||
.clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity),
|
||||
.clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity), // ignore_clamp_double_lint
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
import 'package:vector_math/vector_math_64.dart' show Quad, Vector3, Matrix4;
|
||||
@ -386,7 +387,7 @@ class InteractiveViewer extends StatefulWidget {
|
||||
// the point.
|
||||
final Vector3 l1P = point - l1;
|
||||
final Vector3 l1L2 = l2 - l1;
|
||||
final double fraction = (l1P.dot(l1L2) / lengthSquared).clamp(0.0, 1.0);
|
||||
final double fraction = clampDouble(l1P.dot(l1L2) / lengthSquared, 0.0, 1.0);
|
||||
return l1 + l1L2 * fraction;
|
||||
}
|
||||
|
||||
@ -659,7 +660,7 @@ class _InteractiveViewerState extends State<InteractiveViewer> with TickerProvid
|
||||
_viewport.height / _boundaryRect.height,
|
||||
),
|
||||
);
|
||||
final double clampedTotalScale = totalScale.clamp(
|
||||
final double clampedTotalScale = clampDouble(totalScale,
|
||||
widget.minScale,
|
||||
widget.maxScale,
|
||||
);
|
||||
|
||||
@ -732,7 +732,7 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
|
||||
double pixels, minRange, maxRange, correctionOffset;
|
||||
double extra = 0.0;
|
||||
if (innerPosition.pixels == innerPosition.minScrollExtent) {
|
||||
pixels = _outerPosition!.pixels.clamp(
|
||||
pixels = clampDouble(_outerPosition!.pixels,
|
||||
_outerPosition!.minScrollExtent,
|
||||
_outerPosition!.maxScrollExtent,
|
||||
); // TODO(ianh): gracefully handle out-of-range outer positions
|
||||
@ -799,7 +799,7 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
|
||||
|
||||
double unnestOffset(double value, _NestedScrollPosition source) {
|
||||
if (source == _outerPosition)
|
||||
return value.clamp(
|
||||
return clampDouble(value,
|
||||
_outerPosition!.minScrollExtent,
|
||||
_outerPosition!.maxScrollExtent,
|
||||
);
|
||||
@ -810,7 +810,7 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont
|
||||
|
||||
double nestOffset(double value, _NestedScrollPosition target) {
|
||||
if (target == _outerPosition)
|
||||
return value.clamp(
|
||||
return clampDouble(value,
|
||||
_outerPosition!.minScrollExtent,
|
||||
_outerPosition!.maxScrollExtent,
|
||||
);
|
||||
@ -1212,7 +1212,7 @@ class _NestedScrollPosition extends ScrollPosition implements ScrollActivityDele
|
||||
// 0.0, representing the end of the overscrolled portion.
|
||||
: pixels < 0.0 ? 0.0 : math.max(maxScrollExtent, pixels);
|
||||
final double oldPixels = pixels;
|
||||
final double newPixels = (pixels - delta).clamp(min, max);
|
||||
final double newPixels = clampDouble(pixels - delta, min, max);
|
||||
final double clampedDelta = newPixels - pixels;
|
||||
if (clampedDelta == 0.0)
|
||||
return delta;
|
||||
@ -1268,7 +1268,7 @@ class _NestedScrollPosition extends ScrollPosition implements ScrollActivityDele
|
||||
final double max = delta < 0.0
|
||||
? double.infinity
|
||||
: math.max(maxScrollExtent, pixels);
|
||||
final double newPixels = (pixels + delta).clamp(min, max);
|
||||
final double newPixels = clampDouble(pixels + delta, min, max);
|
||||
final double clampedDelta = newPixels - pixels;
|
||||
if (clampedDelta == 0.0)
|
||||
return delta;
|
||||
@ -1494,7 +1494,7 @@ class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity {
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
value = value.clamp(metrics.minRange, metrics.maxRange);
|
||||
value = clampDouble(value, metrics.minRange, metrics.maxRange);
|
||||
done = true;
|
||||
}
|
||||
final bool result = super.applyMoveTo(value + metrics.correctionOffset);
|
||||
|
||||
@ -255,10 +255,10 @@ class _GlowingOverscrollIndicatorState extends State<GlowingOverscrollIndicator>
|
||||
final Offset position = renderer.globalToLocal(notification.dragDetails!.globalPosition);
|
||||
switch (notification.metrics.axis) {
|
||||
case Axis.horizontal:
|
||||
controller!.pull(notification.overscroll.abs(), size.width, position.dy.clamp(0.0, size.height), size.height);
|
||||
controller!.pull(notification.overscroll.abs(), size.width, clampDouble(position.dy, 0.0, size.height), size.height);
|
||||
break;
|
||||
case Axis.vertical:
|
||||
controller!.pull(notification.overscroll.abs(), size.height, position.dx.clamp(0.0, size.width), size.width);
|
||||
controller!.pull(notification.overscroll.abs(), size.height, clampDouble(position.dx, 0.0, size.width), size.width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -405,9 +405,9 @@ class _GlowController extends ChangeNotifier {
|
||||
assert(velocity >= 0.0);
|
||||
_pullRecedeTimer?.cancel();
|
||||
_pullRecedeTimer = null;
|
||||
velocity = velocity.clamp(_minVelocity, _maxVelocity);
|
||||
velocity = clampDouble(velocity, _minVelocity, _maxVelocity);
|
||||
_glowOpacityTween.begin = _state == _GlowState.idle ? 0.3 : _glowOpacity.value;
|
||||
_glowOpacityTween.end = (velocity * _velocityGlowFactor).clamp(_glowOpacityTween.begin!, _maxOpacity);
|
||||
_glowOpacityTween.end = clampDouble(velocity * _velocityGlowFactor, _glowOpacityTween.begin!, _maxOpacity);
|
||||
_glowSizeTween.begin = _glowSize.value;
|
||||
_glowSizeTween.end = math.min(0.025 + 7.5e-7 * velocity * velocity, 1.0);
|
||||
_glowController.duration = Duration(milliseconds: (0.15 + velocity * 0.02).round());
|
||||
@ -716,7 +716,7 @@ class _StretchingOverscrollIndicatorState extends State<StretchingOverscrollIndi
|
||||
final double viewportDimension = notification.metrics.viewportDimension;
|
||||
final double distanceForPull =
|
||||
(notification.overscroll.abs() / viewportDimension) + _stretchController.pullDistance;
|
||||
final double clampedOverscroll = distanceForPull.clamp(0, 1.0);
|
||||
final double clampedOverscroll = clampDouble(distanceForPull, 0, 1.0);
|
||||
_stretchController.pull(clampedOverscroll);
|
||||
}
|
||||
}
|
||||
@ -845,7 +845,7 @@ class _StretchController extends ChangeNotifier {
|
||||
/// The velocity must be positive.
|
||||
void absorbImpact(double velocity) {
|
||||
assert(velocity >= 0.0);
|
||||
velocity = velocity.clamp(1, 10000);
|
||||
velocity = clampDouble(velocity, 1, 10000);
|
||||
_stretchSizeTween.begin = _stretchSize.value;
|
||||
_stretchSizeTween.end = math.min(_stretchIntensity + (_flingFriction / velocity), 1.0);
|
||||
_stretchController.duration = Duration(milliseconds: (velocity * 0.02).round());
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart' show precisionErrorTolerance;
|
||||
import 'package:flutter/foundation.dart' show precisionErrorTolerance, clampDouble;
|
||||
import 'package:flutter/gestures.dart' show DragStartBehavior;
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
@ -296,7 +296,7 @@ class PageMetrics extends FixedScrollMetrics {
|
||||
|
||||
/// The current page displayed in the [PageView].
|
||||
double? get page {
|
||||
return math.max(0.0, pixels.clamp(minScrollExtent, maxScrollExtent)) /
|
||||
return math.max(0.0, clampDouble(pixels, minScrollExtent, maxScrollExtent)) /
|
||||
math.max(1.0, viewportDimension * viewportFraction);
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
|
||||
);
|
||||
return !hasPixels || !hasContentDimensions
|
||||
? null
|
||||
: _cachedPage ?? getPageFromPixels(pixels.clamp(minScrollExtent, maxScrollExtent), viewportDimension);
|
||||
: _cachedPage ?? getPageFromPixels(clampDouble(pixels, minScrollExtent, maxScrollExtent), viewportDimension);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -116,9 +116,9 @@ mixin ScrollMetrics {
|
||||
assert(minScrollExtent <= maxScrollExtent);
|
||||
return viewportDimension
|
||||
// "above" overscroll value
|
||||
- (minScrollExtent - pixels).clamp(0, viewportDimension)
|
||||
- clampDouble(minScrollExtent - pixels, 0, viewportDimension)
|
||||
// "below" overscroll value
|
||||
- (pixels - maxScrollExtent).clamp(0, viewportDimension);
|
||||
- clampDouble(pixels - maxScrollExtent, 0, viewportDimension);
|
||||
}
|
||||
|
||||
/// The quantity of content conceptually "below" the viewport in the scrollable.
|
||||
|
||||
@ -554,7 +554,7 @@ class RangeMaintainingScrollPhysics extends ScrollPhysics {
|
||||
double result = super.adjustPositionForNewDimensions(oldPosition: oldPosition, newPosition: newPosition, isScrolling: isScrolling, velocity: velocity);
|
||||
if (enforceBoundary) {
|
||||
// ...but if they put us out of range then reinforce the boundary.
|
||||
result = result.clamp(newPosition.minScrollExtent, newPosition.maxScrollExtent);
|
||||
result = clampDouble(result, newPosition.minScrollExtent, newPosition.maxScrollExtent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -710,16 +710,16 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
double target;
|
||||
switch (alignmentPolicy) {
|
||||
case ScrollPositionAlignmentPolicy.explicit:
|
||||
target = viewport.getOffsetToReveal(object, alignment, rect: targetRect).offset.clamp(minScrollExtent, maxScrollExtent);
|
||||
target = clampDouble(viewport.getOffsetToReveal(object, alignment, rect: targetRect).offset, minScrollExtent, maxScrollExtent);
|
||||
break;
|
||||
case ScrollPositionAlignmentPolicy.keepVisibleAtEnd:
|
||||
target = viewport.getOffsetToReveal(object, 1.0, rect: targetRect).offset.clamp(minScrollExtent, maxScrollExtent);
|
||||
target = clampDouble(viewport.getOffsetToReveal(object, 1.0, rect: targetRect).offset, minScrollExtent, maxScrollExtent);
|
||||
if (target < pixels) {
|
||||
target = pixels;
|
||||
}
|
||||
break;
|
||||
case ScrollPositionAlignmentPolicy.keepVisibleAtStart:
|
||||
target = viewport.getOffsetToReveal(object, 0.0, rect: targetRect).offset.clamp(minScrollExtent, maxScrollExtent);
|
||||
target = clampDouble(viewport.getOffsetToReveal(object, 0.0, rect: targetRect).offset, minScrollExtent, maxScrollExtent);
|
||||
if (target > pixels) {
|
||||
target = pixels;
|
||||
}
|
||||
@ -824,7 +824,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
|
||||
assert(clamp != null);
|
||||
|
||||
if (clamp!)
|
||||
to = to.clamp(minScrollExtent, maxScrollExtent);
|
||||
to = clampDouble(to, minScrollExtent, maxScrollExtent);
|
||||
|
||||
return super.moveTo(to, duration: duration, curve: curve);
|
||||
}
|
||||
|
||||
@ -212,13 +212,13 @@ class ClampingScrollSimulation extends Simulation {
|
||||
|
||||
@override
|
||||
double x(double time) {
|
||||
final double t = (time / _duration).clamp(0.0, 1.0);
|
||||
final double t = clampDouble(time / _duration, 0.0, 1.0);
|
||||
return position + _distance * _flingDistancePenetration(t) * velocity.sign;
|
||||
}
|
||||
|
||||
@override
|
||||
double dx(double time) {
|
||||
final double t = (time / _duration).clamp(0.0, 1.0);
|
||||
final double t = clampDouble(time / _duration, 0.0, 1.0);
|
||||
return _distance * _flingVelocityPenetration(t) * velocity.sign / _duration;
|
||||
}
|
||||
|
||||
|
||||
@ -539,8 +539,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
|
||||
// Thumb extent reflects fraction of content visible, as long as this
|
||||
// isn't less than the absolute minimum size.
|
||||
// _totalContentExtent >= viewportDimension, so (_totalContentExtent - _mainAxisPadding) > 0
|
||||
final double fractionVisible = ((_lastMetrics!.extentInside - _mainAxisPadding) / (_totalContentExtent - _mainAxisPadding))
|
||||
.clamp(0.0, 1.0);
|
||||
final double fractionVisible = clampDouble(
|
||||
(_lastMetrics!.extentInside - _mainAxisPadding) /
|
||||
(_totalContentExtent - _mainAxisPadding),
|
||||
0.0,
|
||||
1.0);
|
||||
|
||||
final double thumbExtent = math.max(
|
||||
math.min(_trackExtent, minOverscrollLength),
|
||||
@ -563,11 +566,11 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
|
||||
// [0.8, 1.0] to [0.0, 1.0], so 0% to 20% of overscroll will produce
|
||||
// values for the thumb that range between minLength and the smallest
|
||||
// possible value, minOverscrollLength.
|
||||
: safeMinLength * (1.0 - fractionOverscrolled.clamp(0.0, 0.2) / 0.2);
|
||||
: safeMinLength * (1.0 - clampDouble(fractionOverscrolled, 0.0, 0.2) / 0.2);
|
||||
|
||||
// The `thumbExtent` should be no greater than `trackSize`, otherwise
|
||||
// the scrollbar may scroll towards the wrong direction.
|
||||
return thumbExtent.clamp(newMinLength, _trackExtent);
|
||||
return clampDouble(thumbExtent, newMinLength, _trackExtent);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -611,7 +614,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter {
|
||||
final double scrollableExtent = metrics.maxScrollExtent - metrics.minScrollExtent;
|
||||
|
||||
final double fractionPast = (scrollableExtent > 0)
|
||||
? ((metrics.pixels - metrics.minScrollExtent) / scrollableExtent).clamp(0.0, 1.0)
|
||||
? clampDouble((metrics.pixels - metrics.minScrollExtent) / scrollableExtent, 0.0, 1.0)
|
||||
: 0;
|
||||
|
||||
return (_isReversed ? 1 - fractionPast : fractionPast) * (_trackExtent - thumbExtent);
|
||||
@ -1608,7 +1611,7 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.macOS:
|
||||
case TargetPlatform.windows:
|
||||
newPosition = newPosition.clamp(position.minScrollExtent, position.maxScrollExtent);
|
||||
newPosition = clampDouble(newPosition, position.minScrollExtent, position.maxScrollExtent);
|
||||
break;
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.android:
|
||||
|
||||
@ -60,7 +60,7 @@ class SliverFillViewport extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _SliverFractionalPadding(
|
||||
viewportFraction: padEnds ? (1 - viewportFraction).clamp(0, 1) / 2 : 0,
|
||||
viewportFraction: padEnds ? clampDouble(1 - viewportFraction, 0, 1) / 2 : 0,
|
||||
sliver: _SliverFillViewportRenderObjectWidget(
|
||||
viewportFraction: viewportFraction,
|
||||
delegate: delegate,
|
||||
|
||||
16
packages/flutter/test/foundation/math_test.dart
Normal file
16
packages/flutter/test/foundation/math_test.dart
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('clampDouble', () {
|
||||
expect(clampDouble(-1.0, 0.0, 1.0), equals(0.0));
|
||||
expect(clampDouble(2.0, 0.0, 1.0), equals(1.0));
|
||||
expect(clampDouble(double.infinity, 0.0, 1.0), equals(1.0));
|
||||
expect(clampDouble(-double.infinity, 0.0, 1.0), equals(0.0));
|
||||
expect(clampDouble(double.nan, 0.0, double.infinity), equals(double.infinity));
|
||||
});
|
||||
}
|
||||
@ -15,6 +15,7 @@ import 'dart:math' as math show pi;
|
||||
import 'dart:ui' show lerpDouble, Offset;
|
||||
import 'dart:ui' as ui show Paint, Path, Canvas;
|
||||
|
||||
import 'package:flutter/foundation.dart' show clampDouble;
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user