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