Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4ae1b5f4
Unverified
Commit
4ae1b5f4
authored
Feb 07, 2018
by
amirh
Committed by
GitHub
Feb 07, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Paint the shape border in the Material widget (#14383)
parent
3e1ef19f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
126 additions
and
9 deletions
+126
-9
material.dart
packages/flutter/lib/src/material/material.dart
+50
-6
material_test.dart
packages/flutter/test/material/material_test.dart
+60
-0
mock_canvas.dart
packages/flutter/test/rendering/mock_canvas.dart
+16
-3
No files found.
packages/flutter/lib/src/material/material.dart
View file @
4ae1b5f4
...
...
@@ -130,6 +130,10 @@ abstract class MaterialInkController {
/// rounded edges. The edge radii is specified by [kMaterialEdges].
/// - [MaterialType.transparency]: the default material shape is a rectangle.
///
/// ## Border
///
/// If [shape] is not null, then its border will also be painted (if any).
///
/// ## Layout change notifications
///
/// If the layout changes (e.g. because there's a list on the material, and it's
...
...
@@ -327,7 +331,7 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
final
ShapeBorder
shape
=
_getShape
();
if
(
widget
.
type
==
MaterialType
.
transparency
)
return
_
clipToShape
(
shape:
shape
,
contents:
contents
);
return
_
transparentInterior
(
shape:
shape
,
contents:
contents
);
return
new
_MaterialInterior
(
curve:
Curves
.
fastOutSlowIn
,
...
...
@@ -338,12 +342,14 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
shadowColor:
widget
.
shadowColor
,
child:
contents
,
);
}
static
Widget
_
clipToShape
({
ShapeBorder
shape
,
Widget
contents
})
{
static
Widget
_
transparentInterior
({
ShapeBorder
shape
,
Widget
contents
})
{
return
new
ClipPath
(
child:
contents
,
child:
new
_ShapeBorderPaint
(
child:
contents
,
shape:
shape
,
),
clipper:
new
ShapeBorderClipper
(
shape:
shape
,
),
...
...
@@ -625,10 +631,14 @@ class _MaterialInteriorState extends AnimatedWidgetBaseState<_MaterialInterior>
@override
Widget
build
(
BuildContext
context
)
{
final
ShapeBorder
shape
=
_border
.
evaluate
(
animation
);
return
new
PhysicalShape
(
child:
widget
.
child
,
child:
new
_ShapeBorderPaint
(
child:
widget
.
child
,
shape:
shape
,
),
clipper:
new
ShapeBorderClipper
(
shape:
_border
.
evaluate
(
animation
)
,
shape:
shape
,
textDirection:
Directionality
.
of
(
context
)
),
elevation:
_elevation
.
evaluate
(
animation
),
...
...
@@ -637,3 +647,37 @@ class _MaterialInteriorState extends AnimatedWidgetBaseState<_MaterialInterior>
);
}
}
class
_ShapeBorderPaint
extends
StatelessWidget
{
const
_ShapeBorderPaint
({
@required
this
.
child
,
@required
this
.
shape
,
});
final
Widget
child
;
final
ShapeBorder
shape
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
CustomPaint
(
child:
child
,
foregroundPainter:
new
_ShapeBorderPainter
(
shape
,
Directionality
.
of
(
context
)),
);
}
}
class
_ShapeBorderPainter
extends
CustomPainter
{
_ShapeBorderPainter
(
this
.
border
,
this
.
textDirection
);
final
ShapeBorder
border
;
final
TextDirection
textDirection
;
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
border
.
paint
(
canvas
,
Offset
.
zero
&
size
,
textDirection:
textDirection
);
}
@override
bool
shouldRepaint
(
_ShapeBorderPainter
oldDelegate
)
{
return
oldDelegate
.
border
!=
border
;
}
}
packages/flutter/test/material/material_test.dart
View file @
4ae1b5f4
...
...
@@ -7,6 +7,8 @@ import 'package:flutter/painting.dart';
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../rendering/mock_canvas.dart'
;
class
NotifyMaterial
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -404,4 +406,62 @@ void main() {
));
});
});
group
(
'Border painting'
,
()
{
testWidgets
(
'border is painted on physical layers'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
materialKey
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
Material
(
key:
materialKey
,
type:
MaterialType
.
button
,
child:
const
SizedBox
(
width:
100.0
,
height:
100.0
),
color:
const
Color
(
0xFF0000FF
),
shape:
const
CircleBorder
(
side:
const
BorderSide
(
width:
2.0
,
color:
const
Color
(
0xFF0000FF
),
)
),
)
);
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byKey
(
materialKey
));
expect
(
box
,
paints
..
circle
());
});
testWidgets
(
'border is painted for transparent material'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
materialKey
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
Material
(
key:
materialKey
,
type:
MaterialType
.
transparency
,
child:
const
SizedBox
(
width:
100.0
,
height:
100.0
),
shape:
const
CircleBorder
(
side:
const
BorderSide
(
width:
2.0
,
color:
const
Color
(
0xFF0000FF
),
)
),
)
);
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byKey
(
materialKey
));
expect
(
box
,
paints
..
circle
());
});
testWidgets
(
'border is not painted for when border side is none'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
materialKey
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
Material
(
key:
materialKey
,
type:
MaterialType
.
transparency
,
child:
const
SizedBox
(
width:
100.0
,
height:
100.0
),
shape:
const
CircleBorder
(),
)
);
final
RenderBox
box
=
tester
.
renderObject
(
find
.
byKey
(
materialKey
));
expect
(
box
,
isNot
(
paints
..
circle
()));
});
});
}
packages/flutter/test/rendering/mock_canvas.dart
View file @
4ae1b5f4
...
...
@@ -42,7 +42,7 @@ import 'recording_canvas.dart';
/// To match something which asserts instead of painting, see [paintsAssertion].
PaintPattern
get
paints
=>
new
_TestRecordingCanvasPatternMatcher
();
/// Matches objects or functions that
paint an empty display list
.
/// Matches objects or functions that
does not paint anything on the canvas
.
Matcher
get
paintsNothing
=>
new
_TestRecordingCanvasPaintsNothingMatcher
();
/// Matches objects or functions that assert when they try to paint.
...
...
@@ -539,14 +539,27 @@ class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatch
@override
bool
_evaluatePredicates
(
Iterable
<
RecordedInvocation
>
calls
,
StringBuffer
description
)
{
if
(
calls
.
isEmpty
)
final
Iterable
<
RecordedInvocation
>
paintingCalls
=
_filterCanvasCalls
(
calls
);
if
(
paintingCalls
.
isEmpty
)
return
true
;
description
.
write
(
'painted something, the first call having the following stack:
\n
'
'
${
c
alls.first.stackToString(indent: " ")}
\n
'
'
${
paintingC
alls.first.stackToString(indent: " ")}
\n
'
);
return
false
;
}
static
const
List
<
Symbol
>
_nonPaintingOperations
=
const
<
Symbol
>
[
#save
,
#restore
,
];
// Filters out canvas calls that are not painting anything.
static
Iterable
<
RecordedInvocation
>
_filterCanvasCalls
(
Iterable
<
RecordedInvocation
>
canvasCalls
)
{
return
canvasCalls
.
where
((
RecordedInvocation
canvasCall
)
=>
!
_nonPaintingOperations
.
contains
(
canvasCall
.
invocation
.
memberName
)
);
}
}
class
_TestRecordingCanvasPaintsAssertionMatcher
extends
Matcher
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment