Unverified Commit 74645b43 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Fix `NavigationBar` indicator ripple doesn't account for label height (#117473)

parent 589f2eb9
......@@ -462,26 +462,17 @@ class _NavigationDestinationBuilder extends StatelessWidget {
final _NavigationDestinationInfo info = _NavigationDestinationInfo.of(context);
final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context);
final NavigationBarThemeData defaults = _defaultsFor(context);
final GlobalKey labelKey = GlobalKey();
final bool selected = info.selectedIndex == info.index;
final double labelPadding;
switch (info.labelBehavior) {
case NavigationDestinationLabelBehavior.alwaysShow:
labelPadding = 8;
break;
case NavigationDestinationLabelBehavior.onlyShowSelected:
labelPadding = selected ? 8 : 0;
break;
case NavigationDestinationLabelBehavior.alwaysHide:
labelPadding = 0;
break;
}
return _NavigationBarDestinationSemantics(
child: _NavigationBarDestinationTooltip(
message: tooltip ?? label,
child: _IndicatorInkWell(
key: UniqueKey(),
labelPadding: labelPadding,
labelKey: labelKey,
labelBehavior: info.labelBehavior,
selected: selected,
customBorder: navigationBarTheme.indicatorShape ?? defaults.indicatorShape,
onTap: info.onTap,
child: Row(
......@@ -489,6 +480,7 @@ class _NavigationDestinationBuilder extends StatelessWidget {
Expanded(
child: _NavigationBarDestinationLayout(
icon: buildIcon(context),
labelKey: labelKey,
label: buildLabel(context),
),
),
......@@ -503,7 +495,9 @@ class _NavigationDestinationBuilder extends StatelessWidget {
class _IndicatorInkWell extends InkResponse {
const _IndicatorInkWell({
super.key,
required this.labelPadding,
required this.labelKey,
required this.labelBehavior,
required this.selected,
super.customBorder,
super.onTap,
super.child,
......@@ -512,10 +506,26 @@ class _IndicatorInkWell extends InkResponse {
highlightColor: Colors.transparent,
);
final double labelPadding;
final GlobalKey labelKey;
final NavigationDestinationLabelBehavior labelBehavior;
final bool selected;
@override
RectCallback? getRectCallback(RenderBox referenceBox) {
final RenderBox labelBox = labelKey.currentContext!.findRenderObject()! as RenderBox;
final Rect labelRect = labelBox.localToGlobal(Offset.zero) & labelBox.size;
final double labelPadding;
switch (labelBehavior) {
case NavigationDestinationLabelBehavior.alwaysShow:
labelPadding = labelRect.height / 2;
break;
case NavigationDestinationLabelBehavior.onlyShowSelected:
labelPadding = selected ? labelRect.height / 2 : 0;
break;
case NavigationDestinationLabelBehavior.alwaysHide:
labelPadding = 0;
break;
}
final double indicatorOffsetX = referenceBox.size.width / 2;
final double indicatorOffsetY = referenceBox.size.height / 2 - labelPadding;
......@@ -765,6 +775,7 @@ class _NavigationBarDestinationLayout extends StatelessWidget {
/// 3 [NavigationBar].
const _NavigationBarDestinationLayout({
required this.icon,
required this.labelKey,
required this.label,
});
......@@ -773,6 +784,11 @@ class _NavigationBarDestinationLayout extends StatelessWidget {
/// See [NavigationDestination.icon].
final Widget icon;
/// The global key for the label of this destination.
///
/// This is used to determine the position of the label relative to the icon.
final GlobalKey labelKey;
/// The label widget that sits below the icon.
///
/// This widget will sometimes be faded out, depending on
......@@ -782,7 +798,6 @@ class _NavigationBarDestinationLayout extends StatelessWidget {
final Widget label;
static final Key _iconKey = UniqueKey();
static final Key _labelKey = UniqueKey();
@override
Widget build(BuildContext context) {
......@@ -806,7 +821,7 @@ class _NavigationBarDestinationLayout extends StatelessWidget {
alwaysIncludeSemantics: true,
opacity: animation,
child: RepaintBoundary(
key: _labelKey,
key: labelKey,
child: label,
),
),
......
......@@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
library;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -161,6 +167,48 @@ void main() {
expect(_barMaterial(tester).elevation, elevation);
expect(_labelBehavior(tester), labelBehavior);
});
testWidgets('Custom label style renders ink ripple properly', (WidgetTester tester) async {
Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) {
return MaterialApp(
theme: ThemeData(
navigationBarTheme: const NavigationBarThemeData(
labelTextStyle: MaterialStatePropertyAll<TextStyle>(
TextStyle(fontSize: 25, color: Color(0xff0000ff)),
),
),
useMaterial3: true,
),
home: Scaffold(
bottomNavigationBar: Center(
child: NavigationBar(
labelBehavior: labelBehavior,
destinations: const <Widget>[
NavigationDestination(
icon: SizedBox(),
label: 'AC',
),
NavigationDestination(
icon: SizedBox(),
label: 'Alarm',
),
],
onDestinationSelected: (int i) { },
),
),
),
);
}
await tester.pumpWidget(buildWidget());
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.byType(NavigationDestination).last));
await tester.pumpAndSettle();
await expectLater(find.byType(NavigationBar), matchesGoldenFile('indicator_custom_label_style.png'));
});
}
List<NavigationDestination> _destinations() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment