forked from flutter/plugins
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added an example for IndexedStack widget (#105318)
* Added an example for IndexedStack * Added tests for the IndexedStack example * Fixed type issue for onSubmitted callback functions * Fixed documentation and moved files to their appropriate places * Fixed documentation and moved files to their appropriate places * Moved test files to their appropriate places * Moved test files to their appropriate places * Fixed file path in documentation * Remove trailing space * Formatting changes * Remove extra line * Further formatting changes * Further formatting changes * fix comma and inline Co-authored-by: Greg Spencer <[email protected]> * Formatting * indentation and formatting * Formatting * Formatting * Formatting * Removed duplicate chevron * better wording on documentation Co-authored-by: Tong Mu <[email protected]> * Added testing for state preservation Co-authored-by: Greg Spencer <[email protected]> Co-authored-by: Tong Mu <[email protected]>
- Loading branch information
1 parent
38df107
commit 0825603
Showing
3 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// 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. | ||
|
||
// Flutter code sample for IndexedStack. | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
void main() => runApp(const MyApp()); | ||
|
||
class MyApp extends StatelessWidget { | ||
const MyApp({super.key}); | ||
|
||
static const String _title = 'Flutter Code Sample'; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
title: _title, | ||
home: Scaffold( | ||
appBar: AppBar(title: const Text(_title)), | ||
body: const MyStatefulWidget(), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class MyStatefulWidget extends StatefulWidget { | ||
const MyStatefulWidget({super.key}); | ||
|
||
@override | ||
State<MyStatefulWidget> createState() => _MyStatefulWidgetState(); | ||
} | ||
|
||
class _MyStatefulWidgetState extends State<MyStatefulWidget> { | ||
List<String> names = <String>['Dash', 'John', 'Mary']; | ||
int index = 0; | ||
final TextEditingController fieldText = TextEditingController(); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: <Widget>[ | ||
SizedBox( | ||
width: 300, | ||
child: TextField( | ||
decoration: const InputDecoration( | ||
border: OutlineInputBorder(), | ||
hintText: 'Enter the name for a person to track', | ||
), | ||
onSubmitted: (String value) { | ||
setState(() { | ||
names.add(value); | ||
}); | ||
fieldText.clear(); | ||
}, | ||
controller: fieldText, | ||
), | ||
), | ||
const SizedBox(height: 50), | ||
Row( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: <Widget>[ | ||
GestureDetector( | ||
onTap: () { | ||
setState(() { | ||
if (index == 0) { | ||
index = names.length - 1; | ||
} else { | ||
index -= 1; | ||
} | ||
}); | ||
}, | ||
child: const Icon(key: Key('gesture1'), Icons.chevron_left), | ||
), | ||
Column( | ||
mainAxisAlignment: MainAxisAlignment.center, | ||
children: <Widget>[ | ||
IndexedStack( | ||
index: index, | ||
children: <Widget>[ | ||
for (String name in names) PersonTracker(name: name) | ||
], | ||
) | ||
], | ||
), | ||
GestureDetector( | ||
onTap: () { | ||
setState(() { | ||
if (index == names.length - 1) { | ||
index = 0; | ||
} else { | ||
index += 1; | ||
} | ||
}); | ||
}, | ||
child: const Icon(key: Key('gesture2'), Icons.chevron_right), | ||
), | ||
], | ||
) | ||
], | ||
); | ||
} | ||
} | ||
|
||
class PersonTracker extends StatefulWidget { | ||
const PersonTracker({super.key, required this.name}); | ||
final String name; | ||
@override | ||
State<PersonTracker> createState() => _PersonTrackerState(); | ||
} | ||
|
||
class _PersonTrackerState extends State<PersonTracker> { | ||
int counter = 0; | ||
@override | ||
Widget build(BuildContext context) { | ||
return Container( | ||
key: Key(widget.name), | ||
decoration: BoxDecoration( | ||
color: const Color.fromARGB(255, 239, 248, 255), | ||
border: Border.all(color: const Color.fromARGB(255, 54, 60, 244)), | ||
borderRadius: const BorderRadius.all(Radius.circular(10)), | ||
), | ||
padding: const EdgeInsets.all(16.0), | ||
child: Column( | ||
children: <Widget>[ | ||
Text('Name: ${widget.name}'), | ||
Text('Score: $counter'), | ||
TextButton.icon( | ||
key: Key('increment${widget.name}'), | ||
icon: const Icon(Icons.add), | ||
onPressed: () { | ||
setState(() { | ||
counter += 1; | ||
}); | ||
}, | ||
label: const Text('Increment'), | ||
) | ||
], | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// 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_api_samples/widgets/basic/indexed_stack.0.dart' as example; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
void main() { | ||
testWidgets('has correct forward rendering mechanism', (WidgetTester tester) async { | ||
await tester.pumpWidget(const example.MyApp()); | ||
|
||
final Finder gesture2 = find.byKey(const Key('gesture2')); | ||
final Element containerFinder = find.byKey(const Key('Dash')).evaluate().first; | ||
expect(containerFinder.renderObject!.debugNeedsPaint, false); | ||
final Element containerFinder1 = find.byKey(const Key('John')).evaluate().first; | ||
expect(containerFinder1.renderObject!.debugNeedsPaint, true); | ||
final Element containerFinder2 = find.byKey(const Key('Mary')).evaluate().first; | ||
expect(containerFinder2.renderObject!.debugNeedsPaint, true); | ||
|
||
await tester.tap(gesture2); | ||
await tester.pump(); | ||
expect(containerFinder.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder1.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder2.renderObject!.debugNeedsPaint, true); | ||
|
||
await tester.tap(gesture2); | ||
await tester.pump(); | ||
expect(containerFinder.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder1.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder2.renderObject!.debugNeedsPaint, false); | ||
}); | ||
testWidgets('has correct backward rendering mechanism', (WidgetTester tester) async { | ||
await tester.pumpWidget(const example.MyApp()); | ||
|
||
final Finder gesture1 = find.byKey(const Key('gesture1')); | ||
final Element containerFinder = find.byKey(const Key('Dash')).evaluate().first; | ||
final Element containerFinder1 = find.byKey(const Key('John')).evaluate().first; | ||
final Element containerFinder2 = find.byKey(const Key('Mary')).evaluate().first; | ||
|
||
await tester.tap(gesture1); | ||
await tester.pump(); | ||
expect(containerFinder.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder1.renderObject!.debugNeedsPaint, true); | ||
expect(containerFinder2.renderObject!.debugNeedsPaint, false); | ||
|
||
await tester.tap(gesture1); | ||
await tester.pump(); | ||
expect(containerFinder.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder1.renderObject!.debugNeedsPaint, false); | ||
expect(containerFinder2.renderObject!.debugNeedsPaint, false); | ||
}); | ||
testWidgets('has correct element addition handling', (WidgetTester tester) async { | ||
await tester.pumpWidget(const example.MyApp()); | ||
|
||
expect(find.byType(example.PersonTracker), findsNWidgets(3)); | ||
final Finder textField = find.byType(TextField); | ||
await tester.enterText(textField, 'hello'); | ||
await tester.testTextInput.receiveAction(TextInputAction.done); | ||
await tester.pump(); | ||
expect(find.byType(example.PersonTracker), findsNWidgets(4)); | ||
|
||
await tester.enterText(textField, 'hello1'); | ||
await tester.testTextInput.receiveAction(TextInputAction.done); | ||
await tester.pump(); | ||
expect(find.byType(example.PersonTracker), findsNWidgets(5)); | ||
}); | ||
testWidgets('has state preservation', (WidgetTester tester) async { | ||
await tester.pumpWidget(const example.MyApp()); | ||
|
||
final Finder gesture1 = find.byKey(const Key('gesture1')); | ||
final Finder gesture2 = find.byKey(const Key('gesture2')); | ||
final Finder containerFinder = find.byKey(const Key('Dash')); | ||
final Finder incrementFinder = find.byKey(const Key('incrementDash')); | ||
Finder counterFinder(int score) { | ||
return find.descendant(of: containerFinder, matching: find.text('Score: $score')); | ||
} | ||
|
||
expect(counterFinder(0), findsOneWidget); | ||
await tester.tap(incrementFinder); | ||
await tester.pump(); | ||
|
||
expect(counterFinder(1), findsOneWidget); | ||
|
||
await tester.tap(gesture2); | ||
await tester.pump(); | ||
await tester.tap(gesture1); | ||
await tester.pump(); | ||
|
||
expect(counterFinder(1), findsOneWidget); | ||
expect(counterFinder(0), findsNothing); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters