mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
Add tabs_utils.dart
class (#143937)
This a test utility class for `tabs_test.dart` to prepare the class for Material 3 tests updates. More info in https://github.com/flutter/flutter/issues/139076
This commit is contained in:
parent
e707f0de69
commit
551731697e
File diff suppressed because it is too large
Load diff
230
packages/flutter/test/material/tabs_utils.dart
Normal file
230
packages/flutter/test/material/tabs_utils.dart
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
// 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/rendering.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
// This returns render paragraph of the Tab label text.
|
||||||
|
RenderParagraph getTabText(WidgetTester tester, String text) {
|
||||||
|
return tester.renderObject<RenderParagraph>(find.descendant(
|
||||||
|
of: find.byWidgetPredicate((Widget widget) => widget.runtimeType.toString() == '_TabStyle'),
|
||||||
|
matching: find.text(text),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates and returns a TabController.
|
||||||
|
TabController createTabController({
|
||||||
|
required int length,
|
||||||
|
required TickerProvider vsync,
|
||||||
|
int initialIndex = 0,
|
||||||
|
Duration? animationDuration,
|
||||||
|
}) {
|
||||||
|
final TabController result = TabController(
|
||||||
|
length: length,
|
||||||
|
vsync: vsync,
|
||||||
|
initialIndex: initialIndex,
|
||||||
|
animationDuration: animationDuration,
|
||||||
|
);
|
||||||
|
addTearDown(result.dispose);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This widget is used to test widget state in the tabs_test.dart file.
|
||||||
|
class TabStateMarker extends StatefulWidget {
|
||||||
|
const TabStateMarker({ super.key, this.child });
|
||||||
|
|
||||||
|
final Widget? child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabStateMarkerState createState() => TabStateMarkerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabStateMarkerState extends State<TabStateMarker> {
|
||||||
|
String? marker;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.child ?? Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab controller builder for TabControllerFrame widget.
|
||||||
|
typedef TabControllerFrameBuilder = Widget Function(BuildContext context, TabController controller);
|
||||||
|
|
||||||
|
// This widget creates a TabController and passes it to the builder.
|
||||||
|
class TabControllerFrame extends StatefulWidget {
|
||||||
|
const TabControllerFrame({
|
||||||
|
super.key,
|
||||||
|
required this.length,
|
||||||
|
this.initialIndex = 0,
|
||||||
|
required this.builder,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int length;
|
||||||
|
final int initialIndex;
|
||||||
|
final TabControllerFrameBuilder builder;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabControllerFrameState createState() => TabControllerFrameState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabControllerFrameState extends State<TabControllerFrame> with SingleTickerProviderStateMixin {
|
||||||
|
late TabController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = TabController(
|
||||||
|
vsync: this,
|
||||||
|
length: widget.length,
|
||||||
|
initialIndex: widget.initialIndex,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.builder(context, _controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test utility class to test tab indicator drawing.
|
||||||
|
class TabIndicatorRecordingCanvas extends TestRecordingCanvas {
|
||||||
|
TabIndicatorRecordingCanvas(this.indicatorColor);
|
||||||
|
|
||||||
|
final Color indicatorColor;
|
||||||
|
late Rect indicatorRect;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void drawLine(Offset p1, Offset p2, Paint paint) {
|
||||||
|
// Assuming that the indicatorWeight is 2.0, the default.
|
||||||
|
const double indicatorWeight = 2.0;
|
||||||
|
if (paint.color == indicatorColor) {
|
||||||
|
indicatorRect = Rect.fromPoints(p1, p2).inflate(indicatorWeight / 2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates a Fake implementation of ScrollMetrics.
|
||||||
|
class TabMockScrollMetrics extends Fake implements ScrollMetrics { }
|
||||||
|
|
||||||
|
class TabBarTestScrollPhysics extends ScrollPhysics {
|
||||||
|
const TabBarTestScrollPhysics({ super.parent });
|
||||||
|
|
||||||
|
@override
|
||||||
|
TabBarTestScrollPhysics applyTo(ScrollPhysics? ancestor) {
|
||||||
|
return TabBarTestScrollPhysics(parent: buildParent(ancestor));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
|
||||||
|
return offset == 10 ? 20 : offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final SpringDescription _kDefaultSpring = SpringDescription.withDampingRatio(
|
||||||
|
mass: 0.5,
|
||||||
|
stiffness: 500.0,
|
||||||
|
ratio: 1.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
SpringDescription get spring => _kDefaultSpring;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This widget is used to log the lifecycle of the TabBarView children.
|
||||||
|
class TabBody extends StatefulWidget {
|
||||||
|
const TabBody({
|
||||||
|
super.key,
|
||||||
|
required this.index,
|
||||||
|
required this.log,
|
||||||
|
this.marker = '',
|
||||||
|
});
|
||||||
|
|
||||||
|
final int index;
|
||||||
|
final List<String> log;
|
||||||
|
final String marker;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TabBody> createState() => TabBodyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabBodyState extends State<TabBody> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
widget.log.add('init: ${widget.index}');
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(TabBody oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
// To keep the logging straight, widgets must not change their index.
|
||||||
|
assert(oldWidget.index == widget.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
widget.log.add('dispose: ${widget.index}');
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: widget.marker.isEmpty
|
||||||
|
? Text('${widget.index}')
|
||||||
|
: Text('${widget.index}-${widget.marker}'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This widget is used to test the lifecycle of the TabBarView children with Ink widget.
|
||||||
|
class TabKeepAliveInk extends StatefulWidget {
|
||||||
|
const TabKeepAliveInk({ super.key, required this.title });
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _TabKeepAliveInkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TabKeepAliveInkState extends State<TabKeepAliveInk> with AutomaticKeepAliveClientMixin {
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
return Ink(
|
||||||
|
child: Text(widget.title),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This widget is used to test the lifecycle of the TabBarView children.
|
||||||
|
class TabAlwaysKeepAliveWidget extends StatefulWidget {
|
||||||
|
const TabAlwaysKeepAliveWidget({super.key});
|
||||||
|
|
||||||
|
static String text = 'AlwaysKeepAlive';
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TabAlwaysKeepAliveWidget> createState() => _TabAlwaysKeepAliveWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TabAlwaysKeepAliveWidgetState extends State<TabAlwaysKeepAliveWidget> with AutomaticKeepAliveClientMixin {
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
return Text(TabAlwaysKeepAliveWidget.text);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue