From 1f0041eb96eb2c8e64f71435eefd753b1e6d548c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 15 Jul 2025 20:52:06 -0700 Subject: [PATCH] Add dartpad example to `RoundedSuperellipseBorder` (#172185) Now that Web supports squircles, we can finally add this dartpad example to `RoundedSuperellipseBorder`'s doc. https://github.com/user-attachments/assets/855be690-d9a1-45ec-a262-e0c38cf75b63 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../rounded_superellipse_border.0.dart | 134 ++++++++++++++++++ .../rounded_superellipse_border.0_test.dart | 40 ++++++ .../painting/rounded_rectangle_border.dart | 14 ++ 3 files changed, 188 insertions(+) create mode 100644 examples/api/lib/painting/rounded_superellipse_border/rounded_superellipse_border.0.dart create mode 100644 examples/api/test/painting/rounded_superellipse_border/rounded_superellipse_border.0_test.dart diff --git a/examples/api/lib/painting/rounded_superellipse_border/rounded_superellipse_border.0.dart b/examples/api/lib/painting/rounded_superellipse_border/rounded_superellipse_border.0.dart new file mode 100644 index 00000000000..38dee663f98 --- /dev/null +++ b/examples/api/lib/painting/rounded_superellipse_border/rounded_superellipse_border.0.dart @@ -0,0 +1,134 @@ +// 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/cupertino.dart'; + +/// Flutter code sample for [RoundedSuperellipseBorder]. + +void main() { + runApp(const RoundedSuperellipseBorderExample()); +} + +class RoundedSuperellipseBorderExample extends StatefulWidget { + const RoundedSuperellipseBorderExample({super.key}); + + static final GlobalKey kBorderBoxKey = GlobalKey(); + static final GlobalKey kThicknessSliderKey = GlobalKey(); + static final GlobalKey kRadiusSliderKey = GlobalKey(); + + @override + State createState() => RoundedSuperellipseBorderExampleState(); +} + +class RoundedSuperellipseBorderExampleState extends State { + bool _toggle = true; + double _borderThickness = 4; + double _borderRadius = 69; + + @override + Widget build(BuildContext context) { + final BorderRadiusGeometry radius = BorderRadiusGeometry.circular(_borderRadius); + final BorderSide side = BorderSide(width: _borderThickness, color: const Color(0xFF111111)); + final ShapeBorder shape = _toggle + ? RoundedSuperellipseBorder(side: side, borderRadius: radius) + : RoundedRectangleBorder(side: side, borderRadius: radius); + + return CupertinoApp( + home: CupertinoPageScaffold( + child: Center( + child: Container( + padding: const EdgeInsetsGeometry.all(10), + constraints: const BoxConstraints(maxWidth: 600), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 16, + children: [ + // The border is drawn by this DecoratedBox. + DecoratedBox( + key: RoundedSuperellipseBorderExample.kBorderBoxKey, + decoration: ShapeDecoration(shape: shape, color: const Color(0xFFFFC107)), + child: const SizedBox(width: 400, height: 200), + ), + + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Shape: '), + CupertinoSwitch( + value: _toggle, + onChanged: (bool value) { + setState(() { + _toggle = value; + }); + }, + ), + ConstrainedBox( + constraints: const BoxConstraints(minWidth: 200), + child: Text(_toggle ? 'Rounded Superellipse' : 'Rounded Rect'), + ), + ], + ), + SliderRow( + label: 'Thickness', + slider: CupertinoSlider( + value: _borderThickness, + max: 14, + min: 0.0000001, + onChanged: (double value) { + setState(() { + _borderThickness = value; + }); + }, + ), + valueString: _borderThickness.toStringAsFixed(1), + key: RoundedSuperellipseBorderExample.kThicknessSliderKey, + ), + SliderRow( + label: 'Radius', + slider: CupertinoSlider( + value: _borderRadius, + max: 100, + onChanged: (double value) { + setState(() { + _borderRadius = value; + }); + }, + ), + valueString: _borderRadius.toStringAsFixed(1), + key: RoundedSuperellipseBorderExample.kRadiusSliderKey, + ), + ], + ), + ), + ), + ), + ); + } +} + +class SliderRow extends StatelessWidget { + const SliderRow({ + super.key, + required this.label, + required this.slider, + required this.valueString, + }); + + final String label; + final Widget slider; + final String valueString; + + @override + Widget build(BuildContext context) { + return Flex( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ConstrainedBox(constraints: const BoxConstraints(minWidth: 50), child: Text(label)), + Expanded(child: slider), + ConstrainedBox(constraints: const BoxConstraints(minWidth: 50), child: Text(valueString)), + ], + ); + } +} diff --git a/examples/api/test/painting/rounded_superellipse_border/rounded_superellipse_border.0_test.dart b/examples/api/test/painting/rounded_superellipse_border/rounded_superellipse_border.0_test.dart new file mode 100644 index 00000000000..620efd2a867 --- /dev/null +++ b/examples/api/test/painting/rounded_superellipse_border/rounded_superellipse_border.0_test.dart @@ -0,0 +1,40 @@ +// 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/cupertino.dart'; + +import 'package:flutter_api_samples/painting/rounded_superellipse_border/rounded_superellipse_border.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Smoke Test', (WidgetTester tester) async { + await tester.pumpWidget(const example.RoundedSuperellipseBorderExample()); + expect(find.byType(example.RoundedSuperellipseBorderExample), findsOneWidget); + + final RenderObject borderBox = tester.renderObject( + find.byKey(example.RoundedSuperellipseBorderExample.kBorderBoxKey), + ); + expect(borderBox, paints..rsuperellipse()); + + // Test tapping switches + await tester.tap(find.byType(CupertinoSwitch)); + await tester.pumpAndSettle(); + expect(borderBox, paints..rrect()); + + final Finder radiusSlider = find.descendant( + of: find.byKey(example.RoundedSuperellipseBorderExample.kRadiusSliderKey), + matching: find.byType(CupertinoSlider), + ); + expect(radiusSlider, findsOne); + final Finder thicknessSlider = find.descendant( + of: find.byKey(example.RoundedSuperellipseBorderExample.kThicknessSliderKey), + matching: find.byType(CupertinoSlider), + ); + expect(thicknessSlider, findsOne); + // Preferrably we should test the interaction between the sliders and the + // drawn box, but it seems very hard if the slider thumb doesn't start at + // the left-most position. + }); +} diff --git a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart index 9fe34b9131f..4ec34fe4229 100644 --- a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart @@ -205,6 +205,20 @@ class _RoundedRectangleToCircleBorder extends _ShapeToCircleBorder