Fix: Update CupertinoSheetRoute transition rounded corner (#163700)
Fix: Update CupertinoSheetRoute transition rounded corner fixes: #163334 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
This commit is contained in:
parent
1cd6cb0cdc
commit
b44f717d57
@ -11,6 +11,19 @@ import 'interface_level.dart';
|
|||||||
import 'route.dart';
|
import 'route.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
|
// Smoothing factor applied to the device's top padding (which approximates the corner radius)
|
||||||
|
// to achieve a smoother end to the corner radius animation. A value of 1.0 would use
|
||||||
|
// the full top padding. Values less than 1.0 reduce the effective corner radius, improving
|
||||||
|
// the animation's appearance. Determined through empirical testing.
|
||||||
|
const double _kDeviceCornerRadiusSmoothingFactor = 0.9;
|
||||||
|
|
||||||
|
// Threshold in logical pixels. If the calculated device corner radius (after applying
|
||||||
|
// the smoothing factor) is below this value, the corner radius transition animation will
|
||||||
|
// start from zero. This prevents abrupt transitions for devices with small or negligible
|
||||||
|
// corner radii. This value, combined with the smoothing factor, corresponds roughly
|
||||||
|
// to double the targeted radius of 12. Determined through testing and visual inspection.
|
||||||
|
const double _kRoundedDeviceCornersThreshold = 20.0;
|
||||||
|
|
||||||
// The distance from the top of the open sheet to the top of the screen, as a ratio
|
// The distance from the top of the open sheet to the top of the screen, as a ratio
|
||||||
// of the total height of the screen. Found from eyeballing a simulator running
|
// of the total height of the screen. Found from eyeballing a simulator running
|
||||||
// iOS 18.0.
|
// iOS 18.0.
|
||||||
@ -221,10 +234,15 @@ class CupertinoSheetTransition extends StatefulWidget {
|
|||||||
reverseCurve: reverseCurve,
|
reverseCurve: reverseCurve,
|
||||||
parent: secondaryAnimation,
|
parent: secondaryAnimation,
|
||||||
);
|
);
|
||||||
final double deviceCornerRadius = MediaQuery.maybeViewPaddingOf(context)?.top ?? 0;
|
|
||||||
|
final double deviceCornerRadius =
|
||||||
|
(MediaQuery.maybeViewPaddingOf(context)?.top ?? 0) * _kDeviceCornerRadiusSmoothingFactor;
|
||||||
|
final bool roundedDeviceCorners = deviceCornerRadius > _kRoundedDeviceCornersThreshold;
|
||||||
|
|
||||||
final Animatable<BorderRadiusGeometry> decorationTween = Tween<BorderRadiusGeometry>(
|
final Animatable<BorderRadiusGeometry> decorationTween = Tween<BorderRadiusGeometry>(
|
||||||
begin: BorderRadius.circular(deviceCornerRadius),
|
begin: BorderRadius.vertical(
|
||||||
|
top: Radius.circular(roundedDeviceCorners ? deviceCornerRadius : 0),
|
||||||
|
),
|
||||||
end: BorderRadius.circular(12),
|
end: BorderRadius.circular(12),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -262,7 +280,13 @@ class CupertinoSheetTransition extends StatefulWidget {
|
|||||||
animation: radiusAnimation,
|
animation: radiusAnimation,
|
||||||
child: child,
|
child: child,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return ClipRRect(borderRadius: radiusAnimation.value, child: contrastedChild);
|
return ClipRRect(
|
||||||
|
borderRadius:
|
||||||
|
!secondaryAnimation.isDismissed
|
||||||
|
? radiusAnimation.value
|
||||||
|
: BorderRadius.circular(0),
|
||||||
|
child: contrastedChild,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../widgets/navigator_utils.dart';
|
import '../widgets/navigator_utils.dart';
|
||||||
@ -745,6 +746,74 @@ void main() {
|
|||||||
expect(sheetNavBarHeight, lessThan(homeNavBardHeight));
|
expect(sheetNavBarHeight, lessThan(homeNavBardHeight));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Previous route corner radius goes to same when sheet route is popped', (
|
||||||
|
WidgetTester tester,
|
||||||
|
) async {
|
||||||
|
final GlobalKey scaffoldKey = GlobalKey();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: CupertinoPageScaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
const Text('Page 1'),
|
||||||
|
CupertinoButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push<void>(
|
||||||
|
scaffoldKey.currentContext!,
|
||||||
|
CupertinoSheetRoute<void>(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
child: const Icon(Icons.arrow_back_ios),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Text('Push Page 2'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.text('Page 1'), findsOneWidget);
|
||||||
|
expect(
|
||||||
|
tester
|
||||||
|
.getTopLeft(
|
||||||
|
find.ancestor(of: find.text('Page 1'), matching: find.byType(CupertinoPageScaffold)),
|
||||||
|
)
|
||||||
|
.dy,
|
||||||
|
equals(0.0),
|
||||||
|
);
|
||||||
|
expect(find.byType(Icon), findsNothing);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Push Page 2'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Previous page is still visible behind the new sheet.
|
||||||
|
expect(find.text('Page 1'), findsOneWidget);
|
||||||
|
final Offset pageOneOffset = tester.getTopLeft(
|
||||||
|
find.ancestor(of: find.text('Page 1'), matching: find.byType(CupertinoPageScaffold)),
|
||||||
|
);
|
||||||
|
expect(pageOneOffset.dy, greaterThan(0.0));
|
||||||
|
expect(pageOneOffset.dx, greaterThan(0.0));
|
||||||
|
expect(find.byType(Icon), findsOneWidget);
|
||||||
|
|
||||||
|
// Pop Sheet Route
|
||||||
|
await tester.tap(find.byType(Icon));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
final Finder clipRRectFinder = find.byType(ClipRRect);
|
||||||
|
final Rect clipRect = tester.getRect(clipRRectFinder);
|
||||||
|
expect(clipRect.center, equals(const Offset(400, 300)));
|
||||||
|
});
|
||||||
|
|
||||||
group('drag dismiss gesture', () {
|
group('drag dismiss gesture', () {
|
||||||
Widget dragGestureApp(GlobalKey homeScaffoldKey, GlobalKey sheetScaffoldKey) {
|
Widget dragGestureApp(GlobalKey homeScaffoldKey, GlobalKey sheetScaffoldKey) {
|
||||||
return CupertinoApp(
|
return CupertinoApp(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user