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
a8c9f9c6
Unverified
Commit
a8c9f9c6
authored
Dec 12, 2022
by
Taha Tesser
Committed by
GitHub
Dec 12, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix `NavigationBar` ripple for non-default `NavigationDestinationLabelBehavior` (#116888)
parent
84ed058b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
185 additions
and
27 deletions
+185
-27
navigation_bar.dart
packages/flutter/lib/src/material/navigation_bar.dart
+36
-9
navigation_bar_test.dart
packages/flutter/test/material/navigation_bar_test.dart
+149
-18
No files found.
packages/flutter/lib/src/material/navigation_bar.dart
View file @
a8c9f9c6
...
...
@@ -17,8 +17,8 @@ import 'text_theme.dart';
import
'theme.dart'
;
import
'tooltip.dart'
;
const
double
_kIndicatorHeight
=
64
;
const
double
_kIndicatorWidth
=
32
;
const
double
_kIndicatorHeight
=
32
;
const
double
_kIndicatorWidth
=
64
;
// Examples can assume:
// late BuildContext context;
...
...
@@ -212,6 +212,7 @@ class NavigationBar extends StatelessWidget {
builder:
(
BuildContext
context
,
Animation
<
double
>
animation
)
{
return
_NavigationDestinationInfo
(
index:
i
,
selectedIndex:
selectedIndex
,
totalNumberOfDestinations:
destinations
.
length
,
selectedAnimation:
animation
,
labelBehavior:
effectiveLabelBehavior
,
...
...
@@ -435,10 +436,25 @@ class _NavigationDestinationBuilder extends StatelessWidget {
final
NavigationBarThemeData
navigationBarTheme
=
NavigationBarTheme
.
of
(
context
);
final
NavigationBarThemeData
defaults
=
_defaultsFor
(
context
);
final
bool
selected
=
info
.
selectedIndex
==
info
.
index
;
final
double
labelPadding
;
switch
(
info
.
labelBehavior
)
{
case
NavigationDestinationLabelBehavior
.
alwaysShow
:
labelPadding
=
10
;
break
;
case
NavigationDestinationLabelBehavior
.
onlyShowSelected
:
labelPadding
=
selected
?
10
:
0
;
break
;
case
NavigationDestinationLabelBehavior
.
alwaysHide
:
labelPadding
=
0
;
break
;
}
return
_NavigationBarDestinationSemantics
(
child:
_NavigationBarDestinationTooltip
(
message:
tooltip
??
label
,
child:
_IndicatorInkWell
(
key:
UniqueKey
(),
labelPadding:
labelPadding
,
customBorder:
navigationBarTheme
.
indicatorShape
??
defaults
.
indicatorShape
,
onTap:
info
.
onTap
,
child:
Row
(
...
...
@@ -459,24 +475,28 @@ class _NavigationDestinationBuilder extends StatelessWidget {
class
_IndicatorInkWell
extends
InkResponse
{
const
_IndicatorInkWell
({
super
.
child
,
super
.
onTap
,
super
.
key
,
required
this
.
labelPadding
,
super
.
customBorder
,
super
.
onTap
,
super
.
child
,
})
:
super
(
containedInkWell:
true
,
highlightColor:
Colors
.
transparent
,
);
final
double
labelPadding
;
@override
RectCallback
?
getRectCallback
(
RenderBox
referenceBox
)
{
final
double
indicatorOffsetX
=
referenceBox
.
size
.
width
/
2
;
const
double
indicatorOffsetY
=
30.0
;
final
double
indicatorOffsetY
=
referenceBox
.
size
.
height
/
2
-
labelPadding
;
return
()
{
return
Rect
.
fromCenter
(
center:
Offset
(
indicatorOffsetX
,
indicatorOffsetY
),
width:
_kIndicator
Height
,
height:
_kIndicator
Width
,
width:
_kIndicator
Width
,
height:
_kIndicator
Height
,
);
};
}
...
...
@@ -492,6 +512,7 @@ class _NavigationDestinationInfo extends InheritedWidget {
/// [child] and descendants.
const
_NavigationDestinationInfo
({
required
this
.
index
,
required
this
.
selectedIndex
,
required
this
.
totalNumberOfDestinations
,
required
this
.
selectedAnimation
,
required
this
.
labelBehavior
,
...
...
@@ -529,6 +550,12 @@ class _NavigationDestinationInfo extends InheritedWidget {
/// "Tab 1 of 3", for example.
final
int
index
;
/// This is the index of the currently selected destination.
///
/// This is required for `_IndicatorInkWell` to apply label padding to ripple animations
/// when label behavior is [NavigationDestinationLabelBehavior.onlyShowSelected].
final
int
selectedIndex
;
/// How many total destinations are are in this navigation bar.
///
/// This is required for semantics, so that each destination can have a label
...
...
@@ -593,8 +620,8 @@ class NavigationIndicator extends StatelessWidget {
super
.
key
,
required
this
.
animation
,
this
.
color
,
this
.
width
=
_kIndicator
Height
,
this
.
height
=
_kIndicator
Width
,
this
.
width
=
_kIndicator
Width
,
this
.
height
=
_kIndicator
Height
,
this
.
borderRadius
=
const
BorderRadius
.
all
(
Radius
.
circular
(
16
)),
this
.
shape
,
});
...
...
packages/flutter/test/material/navigation_bar_test.dart
View file @
a8c9f9c6
...
...
@@ -558,24 +558,30 @@ void main() {
});
testWidgets
(
'Navigation indicator renders ripple'
,
(
WidgetTester
tester
)
async
{
final
Widget
widget
=
_buildWidget
(
NavigationBar
(
destinations:
const
<
Widget
>[
NavigationDestination
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
,
),
NavigationDestination
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
,
),
],
onDestinationSelected:
(
int
i
)
{
},
),
);
// This is a regression test for https://github.com/flutter/flutter/issues/116751.
int
selectedIndex
=
0
;
await
tester
.
pumpWidget
(
widget
);
Widget
buildWidget
({
NavigationDestinationLabelBehavior
?
labelBehavior
})
{
return
_buildWidget
(
NavigationBar
(
selectedIndex:
selectedIndex
,
labelBehavior:
labelBehavior
,
destinations:
const
<
Widget
>[
NavigationDestination
(
icon:
Icon
(
Icons
.
ac_unit
),
label:
'AC'
,
),
NavigationDestination
(
icon:
Icon
(
Icons
.
access_alarm
),
label:
'Alarm'
,
),
],
onDestinationSelected:
(
int
i
)
{
},
),
);
}
await
tester
.
pumpWidget
(
buildWidget
());
final
TestGesture
gesture
=
await
tester
.
createGesture
(
kind:
PointerDeviceKind
.
mouse
);
await
gesture
.
addPointer
();
...
...
@@ -583,9 +589,134 @@ void main() {
await
tester
.
pumpAndSettle
();
final
RenderObject
inkFeatures
=
tester
.
allRenderObjects
.
firstWhere
((
RenderObject
object
)
=>
object
.
runtimeType
.
toString
()
==
'_RenderInkFeatures'
);
const
Offset
indicatorCenter
=
Offset
(
600
,
30
);
Offset
indicatorCenter
=
const
Offset
(
600
,
30
);
const
Size
includedIndicatorSize
=
Size
(
64
,
32
);
const
Size
excludedIndicatorSize
=
Size
(
74
,
40
);
// Test ripple when NavigationBar is using `NavigationDestinationLabelBehavior.alwaysShow` (default).
expect
(
inkFeatures
,
paints
..
clipPath
(
pathMatcher:
isPathThat
(
includes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
includedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
includedIndicatorSize
.
height
/
2
)),
],
excludes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
excludedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
excludedIndicatorSize
.
height
/
2
)),
],
),
)
..
circle
(
x:
indicatorCenter
.
dx
,
y:
indicatorCenter
.
dy
,
radius:
35.0
,
color:
const
Color
(
0x0a000000
),
)
);
// Test ripple when NavigationBar is using `NavigationDestinationLabelBehavior.alwaysHide`.
await
tester
.
pumpWidget
(
buildWidget
(
labelBehavior:
NavigationDestinationLabelBehavior
.
alwaysHide
));
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byIcon
(
Icons
.
access_alarm
)));
await
tester
.
pumpAndSettle
();
indicatorCenter
=
const
Offset
(
600
,
40
);
expect
(
inkFeatures
,
paints
..
clipPath
(
pathMatcher:
isPathThat
(
includes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
includedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
includedIndicatorSize
.
height
/
2
)),
],
excludes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
excludedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
excludedIndicatorSize
.
height
/
2
)),
],
),
)
..
circle
(
x:
indicatorCenter
.
dx
,
y:
indicatorCenter
.
dy
,
radius:
35.0
,
color:
const
Color
(
0x0a000000
),
)
);
// Test ripple when NavigationBar is using `NavigationDestinationLabelBehavior.onlyShowSelected`.
await
tester
.
pumpWidget
(
buildWidget
(
labelBehavior:
NavigationDestinationLabelBehavior
.
onlyShowSelected
));
await
gesture
.
moveTo
(
tester
.
getCenter
(
find
.
byIcon
(
Icons
.
access_alarm
)));
await
tester
.
pumpAndSettle
();
expect
(
inkFeatures
,
paints
..
clipPath
(
pathMatcher:
isPathThat
(
includes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
includedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
includedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
includedIndicatorSize
.
height
/
2
)),
],
excludes:
<
Offset
>[
// Left center.
Offset
(
indicatorCenter
.
dx
-
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Top center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
-
(
excludedIndicatorSize
.
height
/
2
)),
// Right center.
Offset
(
indicatorCenter
.
dx
+
(
excludedIndicatorSize
.
width
/
2
),
indicatorCenter
.
dy
),
// Bottom center.
Offset
(
indicatorCenter
.
dx
,
indicatorCenter
.
dy
+
(
excludedIndicatorSize
.
height
/
2
)),
],
),
)
..
circle
(
x:
indicatorCenter
.
dx
,
y:
indicatorCenter
.
dy
,
radius:
35.0
,
color:
const
Color
(
0x0a000000
),
)
);
// Make sure ripple is shifted when selectedIndex changes.
selectedIndex
=
1
;
await
tester
.
pumpWidget
(
buildWidget
(
labelBehavior:
NavigationDestinationLabelBehavior
.
onlyShowSelected
));
await
tester
.
pumpAndSettle
();
indicatorCenter
=
const
Offset
(
600
,
30
);
expect
(
inkFeatures
,
paints
...
...
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