mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
460 lines
19 KiB
Dart
460 lines
19 KiB
Dart
// 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/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:vector_math/vector_math_64.dart' show Vector3;
|
|
|
|
|
|
void main() {
|
|
test('BottomNavigationBarThemeData copyWith, ==, hashCode basics', () {
|
|
expect(const BottomNavigationBarThemeData(), const BottomNavigationBarThemeData().copyWith());
|
|
expect(const BottomNavigationBarThemeData().hashCode, const BottomNavigationBarThemeData().copyWith().hashCode);
|
|
});
|
|
|
|
test('BottomNavigationBarThemeData defaults', () {
|
|
const BottomNavigationBarThemeData themeData = BottomNavigationBarThemeData();
|
|
expect(themeData.backgroundColor, null);
|
|
expect(themeData.elevation, null);
|
|
expect(themeData.selectedIconTheme, null);
|
|
expect(themeData.unselectedIconTheme, null);
|
|
expect(themeData.selectedItemColor, null);
|
|
expect(themeData.unselectedItemColor, null);
|
|
expect(themeData.selectedLabelStyle, null);
|
|
expect(themeData.unselectedLabelStyle, null);
|
|
expect(themeData.showSelectedLabels, null);
|
|
expect(themeData.showUnselectedLabels, null);
|
|
expect(themeData.type, null);
|
|
expect(themeData.landscapeLayout, null);
|
|
expect(themeData.mouseCursor, null);
|
|
|
|
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData(), child: SizedBox());
|
|
expect(theme.data.backgroundColor, null);
|
|
expect(theme.data.elevation, null);
|
|
expect(theme.data.selectedIconTheme, null);
|
|
expect(theme.data.unselectedIconTheme, null);
|
|
expect(theme.data.selectedItemColor, null);
|
|
expect(theme.data.unselectedItemColor, null);
|
|
expect(theme.data.selectedLabelStyle, null);
|
|
expect(theme.data.unselectedLabelStyle, null);
|
|
expect(theme.data.showSelectedLabels, null);
|
|
expect(theme.data.showUnselectedLabels, null);
|
|
expect(theme.data.type, null);
|
|
expect(themeData.landscapeLayout, null);
|
|
expect(themeData.mouseCursor, null);
|
|
});
|
|
|
|
testWidgets('Default BottomNavigationBarThemeData debugFillProperties', (WidgetTester tester) async {
|
|
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
|
const BottomNavigationBarThemeData().debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(description, <String>[]);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async {
|
|
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
|
const BottomNavigationBarThemeData(
|
|
backgroundColor: Color(0xfffffff0),
|
|
elevation: 10.0,
|
|
selectedIconTheme: IconThemeData(size: 1.0),
|
|
unselectedIconTheme: IconThemeData(size: 2.0),
|
|
selectedItemColor: Color(0xfffffff1),
|
|
unselectedItemColor: Color(0xfffffff2),
|
|
selectedLabelStyle: TextStyle(fontSize: 3.0),
|
|
unselectedLabelStyle: TextStyle(fontSize: 4.0),
|
|
showSelectedLabels: true,
|
|
showUnselectedLabels: true,
|
|
type: BottomNavigationBarType.fixed,
|
|
mouseCursor: MaterialStateMouseCursor.clickable,
|
|
).debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(description[0], 'backgroundColor: Color(0xfffffff0)');
|
|
expect(description[1], 'elevation: 10.0');
|
|
|
|
// Ignore instance address for IconThemeData.
|
|
expect(description[2].contains('selectedIconTheme: IconThemeData'), isTrue);
|
|
expect(description[2].contains('(size: 1.0)'), isTrue);
|
|
expect(description[3].contains('unselectedIconTheme: IconThemeData'), isTrue);
|
|
expect(description[3].contains('(size: 2.0)'), isTrue);
|
|
|
|
expect(description[4], 'selectedItemColor: Color(0xfffffff1)');
|
|
expect(description[5], 'unselectedItemColor: Color(0xfffffff2)');
|
|
expect(description[6], 'selectedLabelStyle: TextStyle(inherit: true, size: 3.0)');
|
|
expect(description[7], 'unselectedLabelStyle: TextStyle(inherit: true, size: 4.0)');
|
|
expect(description[8], 'showSelectedLabels: true');
|
|
expect(description[9], 'showUnselectedLabels: true');
|
|
expect(description[10], 'type: BottomNavigationBarType.fixed');
|
|
expect(description[11], 'mouseCursor: MaterialStateMouseCursor(clickable)');
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar is themeable', (WidgetTester tester) async {
|
|
const Color backgroundColor = Color(0xFF000001);
|
|
const Color selectedItemColor = Color(0xFF000002);
|
|
const Color unselectedItemColor = Color(0xFF000003);
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: 10);
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: 11);
|
|
const TextStyle selectedTextStyle = TextStyle(fontSize: 22);
|
|
const TextStyle unselectedTextStyle = TextStyle(fontSize: 21);
|
|
const double elevation = 9.0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
|
backgroundColor: backgroundColor,
|
|
selectedItemColor: selectedItemColor,
|
|
unselectedItemColor: unselectedItemColor,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
elevation: elevation,
|
|
showUnselectedLabels: true,
|
|
showSelectedLabels: true,
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedLabelStyle: selectedTextStyle,
|
|
unselectedLabelStyle: unselectedTextStyle,
|
|
mouseCursor: MaterialStateProperty.resolveWith<MouseCursor?>((Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.selected)) {
|
|
return SystemMouseCursors.grab;
|
|
}
|
|
return SystemMouseCursors.move;
|
|
}),
|
|
),
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder findACTransform = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.ancestor(
|
|
of: find.text('AC'),
|
|
matching: find.byType(Transform),
|
|
),
|
|
);
|
|
final Finder findAlarmTransform = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.ancestor(
|
|
of: find.text('Alarm'),
|
|
matching: find.byType(Transform),
|
|
),
|
|
);
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
|
|
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
|
|
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
|
|
// Unselected label has a font size of 22 but is scaled down to be font size 21.
|
|
expect(
|
|
tester.firstWidget<Transform>(findAlarmTransform).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
|
|
);
|
|
expect(selectedIcon.color, equals(selectedItemColor));
|
|
expect(selectedIcon.fontSize, equals(selectedIconTheme.size));
|
|
expect(unselectedIcon.color, equals(unselectedItemColor));
|
|
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
|
|
// There should not be any [Opacity] or [FadeTransition] widgets
|
|
// since showUnselectedLabels and showSelectedLabels are true.
|
|
final Finder findOpacity = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(Opacity),
|
|
);
|
|
final Finder findFadeTransition = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(FadeTransition),
|
|
);
|
|
expect(findOpacity, findsNothing);
|
|
expect(findFadeTransition, findsNothing);
|
|
expect(_material(tester).elevation, equals(elevation));
|
|
expect(_material(tester).color, equals(backgroundColor));
|
|
|
|
final Offset selectedBarItem = tester.getCenter(findACTransform);
|
|
final Offset unselectedBarItem = tester.getCenter(findAlarmTransform);
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(selectedBarItem);
|
|
await tester.pumpAndSettle();
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
|
await gesture.moveTo(unselectedBarItem);
|
|
await tester.pumpAndSettle();
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.move);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBar properties are taken over the theme values', (WidgetTester tester) async {
|
|
const Color themeBackgroundColor = Color(0xFF000001);
|
|
const Color themeSelectedItemColor = Color(0xFF000002);
|
|
const Color themeUnselectedItemColor = Color(0xFF000003);
|
|
const IconThemeData themeSelectedIconTheme = IconThemeData(size: 10);
|
|
const IconThemeData themeUnselectedIconTheme = IconThemeData(size: 11);
|
|
const TextStyle themeSelectedTextStyle = TextStyle(fontSize: 22);
|
|
const TextStyle themeUnselectedTextStyle = TextStyle(fontSize: 21);
|
|
const double themeElevation = 9.0;
|
|
const BottomNavigationBarLandscapeLayout themeLandscapeLayout = BottomNavigationBarLandscapeLayout.centered;
|
|
const MaterialStateMouseCursor themeCursor = MaterialStateMouseCursor.clickable;
|
|
|
|
const Color backgroundColor = Color(0xFF000004);
|
|
const Color selectedItemColor = Color(0xFF000005);
|
|
const Color unselectedItemColor = Color(0xFF000006);
|
|
const IconThemeData selectedIconTheme = IconThemeData(size: 15);
|
|
const IconThemeData unselectedIconTheme = IconThemeData(size: 16);
|
|
const TextStyle selectedTextStyle = TextStyle(fontSize: 25);
|
|
const TextStyle unselectedTextStyle = TextStyle(fontSize: 26);
|
|
const double elevation = 7.0;
|
|
const BottomNavigationBarLandscapeLayout landscapeLayout = BottomNavigationBarLandscapeLayout.spread;
|
|
const MaterialStateMouseCursor cursor = MaterialStateMouseCursor.textable;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
|
backgroundColor: themeBackgroundColor,
|
|
selectedItemColor: themeSelectedItemColor,
|
|
unselectedItemColor: themeUnselectedItemColor,
|
|
selectedIconTheme: themeSelectedIconTheme,
|
|
unselectedIconTheme: themeUnselectedIconTheme,
|
|
elevation: themeElevation,
|
|
showUnselectedLabels: false,
|
|
showSelectedLabels: false,
|
|
type: BottomNavigationBarType.shifting,
|
|
selectedLabelStyle: themeSelectedTextStyle,
|
|
unselectedLabelStyle: themeUnselectedTextStyle,
|
|
landscapeLayout: themeLandscapeLayout,
|
|
mouseCursor: themeCursor,
|
|
),
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
backgroundColor: backgroundColor,
|
|
selectedItemColor: selectedItemColor,
|
|
unselectedItemColor: unselectedItemColor,
|
|
selectedIconTheme: selectedIconTheme,
|
|
unselectedIconTheme: unselectedIconTheme,
|
|
elevation: elevation,
|
|
showUnselectedLabels: true,
|
|
showSelectedLabels: true,
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedLabelStyle: selectedTextStyle,
|
|
unselectedLabelStyle: unselectedTextStyle,
|
|
landscapeLayout: landscapeLayout,
|
|
mouseCursor: cursor,
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Finder findDescendantOfBottomNavigationBar(Finder finder) {
|
|
return find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: finder,
|
|
);
|
|
}
|
|
|
|
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style!;
|
|
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
|
|
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
|
|
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
|
|
// Unselected label has a font size of 22 but is scaled down to be font size 21.
|
|
expect(
|
|
tester.firstWidget<Transform>(
|
|
findDescendantOfBottomNavigationBar(
|
|
find.ancestor(
|
|
of: find.text('Alarm'),
|
|
matching: find.byType(Transform),
|
|
),
|
|
),
|
|
).transform,
|
|
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize! / selectedTextStyle.fontSize!))),
|
|
);
|
|
expect(selectedIcon.color, equals(selectedItemColor));
|
|
expect(selectedIcon.fontSize, equals(selectedIconTheme.size));
|
|
expect(unselectedIcon.color, equals(unselectedItemColor));
|
|
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
|
|
// There should not be any [Opacity] or [FadeTransition] widgets
|
|
// since showUnselectedLabels and showSelectedLabels are true.
|
|
final Finder findOpacity = findDescendantOfBottomNavigationBar(
|
|
find.byType(Opacity),
|
|
);
|
|
final Finder findFadeTransition = findDescendantOfBottomNavigationBar(
|
|
find.byType(FadeTransition),
|
|
);
|
|
expect(findOpacity, findsNothing);
|
|
expect(findFadeTransition, findsNothing);
|
|
expect(_material(tester).elevation, equals(elevation));
|
|
expect(_material(tester).color, equals(backgroundColor));
|
|
|
|
final Offset barItem = tester.getCenter(
|
|
findDescendantOfBottomNavigationBar(
|
|
find.ancestor(
|
|
of: find.text('AC'),
|
|
matching: find.byType(Transform),
|
|
),
|
|
),
|
|
);
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(barItem);
|
|
await tester.pumpAndSettle();
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBarTheme can be used to hide all labels', (WidgetTester tester) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/66738.
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: false,
|
|
),
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
|
|
final Finder findVisibility = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(Visibility),
|
|
);
|
|
|
|
expect(findVisibility, findsNWidgets(2));
|
|
expect(tester.widget<Visibility>(findVisibility.at(0)).visible, false);
|
|
expect(tester.widget<Visibility>(findVisibility.at(1)).visible, false);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBarTheme can be used to hide selected labels', (WidgetTester tester) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/66738.
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
|
showSelectedLabels: false,
|
|
showUnselectedLabels: true,
|
|
),
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
|
|
final Finder findFadeTransition = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(FadeTransition),
|
|
);
|
|
|
|
expect(findFadeTransition, findsNWidgets(2));
|
|
expect(tester.widget<FadeTransition>(findFadeTransition.at(0)).opacity.value, 0.0);
|
|
expect(tester.widget<FadeTransition>(findFadeTransition.at(1)).opacity.value, 1.0);
|
|
});
|
|
|
|
testWidgets('BottomNavigationBarTheme can be used to hide unselected labels', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
|
|
showSelectedLabels: true,
|
|
showUnselectedLabels: false,
|
|
),
|
|
),
|
|
home: Scaffold(
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
items: const <BottomNavigationBarItem>[
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.ac_unit),
|
|
label: 'AC',
|
|
),
|
|
BottomNavigationBarItem(
|
|
icon: Icon(Icons.access_alarm),
|
|
label: 'Alarm',
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
|
|
final Finder findFadeTransition = find.descendant(
|
|
of: find.byType(BottomNavigationBar),
|
|
matching: find.byType(FadeTransition),
|
|
);
|
|
|
|
expect(findFadeTransition, findsNWidgets(2));
|
|
expect(tester.widget<FadeTransition>(findFadeTransition.at(0)).opacity.value, 1.0);
|
|
expect(tester.widget<FadeTransition>(findFadeTransition.at(1)).opacity.value, 0.0);
|
|
});
|
|
}
|
|
|
|
TextStyle _iconStyle(WidgetTester tester, IconData icon) {
|
|
final RichText iconRichText = tester.widget<RichText>(
|
|
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
|
|
);
|
|
return iconRichText.text.style!;
|
|
}
|
|
|
|
Material _material(WidgetTester tester) {
|
|
return tester.firstWidget<Material>(
|
|
find.descendant(of: find.byType(BottomNavigationBar), matching: find.byType(Material)),
|
|
);
|
|
}
|