Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Added LinearBorder, an OutlinedBorder like BoxBorder (#116940)
Browse files Browse the repository at this point in the history
  • Loading branch information
HansMuller authored Jan 13, 2023
1 parent fb1a151 commit 3a181e4
Show file tree
Hide file tree
Showing 5 changed files with 901 additions and 0 deletions.
303 changes: 303 additions & 0 deletions examples/api/lib/painting/linear_border/linear_border.0.dart
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'),
),
],
),
],
),
),
),
);
}
}
40 changes: 40 additions & 0 deletions examples/api/test/painting/linear_border.0_test.dart
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();
});
}
1 change: 1 addition & 0 deletions packages/flutter/lib/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export 'src/painting/image_provider.dart';
export 'src/painting/image_resolution.dart';
export 'src/painting/image_stream.dart';
export 'src/painting/inline_span.dart';
export 'src/painting/linear_border.dart';
export 'src/painting/matrix_utils.dart';
export 'src/painting/notched_shapes.dart';
export 'src/painting/oval_border.dart';
Expand Down
Loading

0 comments on commit 3a181e4

Please sign in to comment.