-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added LinearBorder, an OutlinedBorder like BoxBorder (#116940)
- Loading branch information
1 parent
fb1a151
commit 3a181e4
Showing
5 changed files
with
901 additions
and
0 deletions.
There are no files selected for viewing
303 changes: 303 additions & 0 deletions
303
examples/api/lib/painting/linear_border/linear_border.0.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
// 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. | ||
|
||
// Examples of LinearBorder and LinearBorderEdge. | ||
|
||
|
||
import 'package:flutter/material.dart'; | ||
|
||
void main() { | ||
runApp(const ExampleApp()); | ||
} | ||
|
||
class ExampleApp extends StatelessWidget { | ||
const ExampleApp({ super.key }); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
theme: ThemeData.light(useMaterial3: true), | ||
home: const Directionality( | ||
textDirection: TextDirection.ltr, // Or try rtl. | ||
child: Home(), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class SampleCard extends StatelessWidget { | ||
const SampleCard({ super.key, required this.title, required this.subtitle, required this.children }); | ||
|
||
final String title; | ||
final String subtitle; | ||
final List<Widget> children; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final ThemeData theme = Theme.of(context); | ||
final TextTheme textTheme = theme.textTheme; | ||
final ColorScheme colorScheme = theme.colorScheme; | ||
|
||
return Card( | ||
child: Padding( | ||
padding: const EdgeInsets.all(16), | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
mainAxisSize: MainAxisSize.min, | ||
children: <Widget>[ | ||
Text(title, style: textTheme.titleMedium), | ||
Text(subtitle, style: textTheme.bodyMedium!.copyWith(color: colorScheme.secondary)), | ||
const SizedBox(height: 16), | ||
Row( | ||
children: List<Widget>.generate(children.length * 2 - 1, (int index) { | ||
return index.isEven ? children[index ~/2] : const SizedBox(width: 16); | ||
}), | ||
), | ||
], | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class Home extends StatefulWidget { | ||
const Home({ super.key }); | ||
|
||
@override | ||
State<Home> createState() => _HomeState(); | ||
} | ||
|
||
class _HomeState extends State<Home> { | ||
final LinearBorder shape0 = LinearBorder.top(); | ||
final LinearBorder shape1 = LinearBorder.top(size: 0); | ||
late LinearBorder shape = shape0; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final ColorScheme colorScheme = Theme.of(context).colorScheme; | ||
final BorderSide primarySide0 = BorderSide(width: 0, color: colorScheme.inversePrimary); // hairline | ||
final BorderSide primarySide2 = BorderSide(width: 2, color: colorScheme.onPrimaryContainer); | ||
final BorderSide primarySide3 = BorderSide(width: 3, color: colorScheme.inversePrimary); | ||
|
||
return Scaffold( | ||
body: SingleChildScrollView( | ||
child: Padding( | ||
padding: const EdgeInsets.all(16), | ||
child: Column( | ||
mainAxisSize: MainAxisSize.min, | ||
children: <Widget>[ | ||
// Demonstrates using LinearBorder.bottom() to define | ||
// an underline border for the standard button types. | ||
// The underline's color and width is defined by the ButtonStyle's | ||
// side parameter. The side can also be specified as a | ||
// LinearBorder parameter and if both are specified then the | ||
// ButtonStyle's side is used. This set up makes it possible | ||
// for a button theme to specify the shape and for indidividual | ||
// buttons to specify the shape border's color and width. | ||
SampleCard( | ||
title: 'LinearBorder.bottom()', | ||
subtitle: 'Standard button widgets', | ||
children: <Widget>[ | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide3, | ||
shape: LinearBorder.bottom(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Text'), | ||
), | ||
OutlinedButton( | ||
style: OutlinedButton.styleFrom( | ||
side: primarySide3, | ||
shape: LinearBorder.bottom(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Outlined'), | ||
), | ||
ElevatedButton( | ||
style: ElevatedButton.styleFrom( | ||
side: primarySide3, | ||
shape: LinearBorder.bottom(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Elevated'), | ||
), | ||
], | ||
), | ||
const SizedBox(height: 32), | ||
// Demonstrates creating LinearBorders with a single edge | ||
// by using the convenience constructors like LinearBorder.start(). | ||
// The edges are drawn with a BorderSide with width:0, which | ||
// means that a "hairline" line is stroked. Wider borders are | ||
// drawn with filled rectangles. | ||
SampleCard( | ||
title: 'LinearBorder', | ||
subtitle: 'Convenience constructors', | ||
children: <Widget>[ | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: LinearBorder.start(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Start()'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: LinearBorder.end(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('End()'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: LinearBorder.top(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Top()'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: LinearBorder.bottom(), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Bottom()'), | ||
), | ||
], | ||
), | ||
const SizedBox(height: 32), | ||
// Demonstrates creating LinearBorders with a single edge | ||
// that's smaller than the button's bounding box. The size | ||
// parameter specifies a percentage of the available space | ||
// and alignment is -1 for start-alignment, 0 for centered, | ||
// and 1 for end-alignment. | ||
SampleCard( | ||
title: 'LinearBorder', | ||
subtitle: 'Size and alignment parameters', | ||
children: <Widget>[ | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide2, | ||
shape: LinearBorder.bottom( | ||
size: 0.5, | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Center'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide2, | ||
shape: LinearBorder.bottom( | ||
size: 0.75, | ||
alignment: -1, | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Start'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide2, | ||
shape: LinearBorder.bottom( | ||
size: 0.75, | ||
alignment: 1, | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('End'), | ||
), | ||
], | ||
), | ||
const SizedBox(height: 32), | ||
// Demonstrates creating LinearBorders with more than one edge. | ||
// In these cases the default constructor is used and each edge | ||
// is defined with one LinearBorderEdge object. | ||
SampleCard( | ||
title: 'LinearBorder', | ||
subtitle: 'LinearBorderEdge parameters', | ||
children: <Widget>[ | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: const LinearBorder( | ||
top: LinearBorderEdge(), | ||
bottom: LinearBorderEdge(), | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Horizontal'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: const LinearBorder( | ||
start: LinearBorderEdge(), | ||
end: LinearBorderEdge(), | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Vertical'), | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide0, | ||
shape: const LinearBorder( | ||
start: LinearBorderEdge(), | ||
bottom: LinearBorderEdge(), | ||
), | ||
), | ||
onPressed: () { }, | ||
child: const Text('Corner'), | ||
), | ||
], | ||
), | ||
const SizedBox(height: 32), | ||
// Demonstrates that changing properties of LinearBorders | ||
// causes them to animate to their new configuration. | ||
SampleCard( | ||
title: 'Interpolation', | ||
subtitle: 'LinearBorder.top() => LinearBorder.top(size: 0)', | ||
children: <Widget>[ | ||
IconButton( | ||
icon: const Icon(Icons.play_arrow), | ||
onPressed: () { | ||
setState(() { | ||
shape = shape == shape0 ? shape1 : shape0; | ||
}); | ||
}, | ||
), | ||
TextButton( | ||
style: TextButton.styleFrom( | ||
side: primarySide3, | ||
shape: shape, | ||
), | ||
onPressed: () { }, | ||
child: const Text('Press Play'), | ||
), | ||
TextButton( | ||
style: ButtonStyle( | ||
side: MaterialStateProperty.resolveWith<BorderSide?>((Set <MaterialState> states) { | ||
return states.contains(MaterialState.hovered) ? primarySide3 : null; | ||
}), | ||
shape: MaterialStateProperty.resolveWith<OutlinedBorder>((Set <MaterialState> states) { | ||
return states.contains(MaterialState.hovered) ? shape0 : shape1; | ||
}), | ||
|
||
), | ||
onPressed: () { }, | ||
child: const Text('Hover'), | ||
), | ||
], | ||
), | ||
], | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/material.dart'; | ||
|
||
import 'package:flutter_api_samples/painting/linear_border/linear_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.ExampleApp(), | ||
); | ||
expect(find.byType(example.Home), findsOneWidget); | ||
|
||
// Scroll the interpolation example into view | ||
|
||
await tester.scrollUntilVisible( | ||
find.byIcon(Icons.play_arrow), | ||
500.0, | ||
scrollable: find.byType(Scrollable), | ||
); | ||
expect(find.byIcon(Icons.play_arrow), findsOneWidget); | ||
|
||
// Run the interpolation example | ||
|
||
await tester.tap(find.byIcon(Icons.play_arrow)); | ||
await tester.pumpAndSettle(); | ||
|
||
await tester.tap(find.byIcon(Icons.play_arrow)); | ||
await tester.pumpAndSettle(); | ||
|
||
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('Interpolation'))); | ||
await gesture.moveTo(tester.getCenter(find.text('Hover'))); | ||
await tester.pumpAndSettle(); | ||
await gesture.moveTo(tester.getCenter(find.text('Interpolation'))); | ||
await tester.pumpAndSettle(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.